Crashing when an Intent is called inside a Recycler View Adapter - java

public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.parentCard.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent=new Intent(context,DetailedView.class);
context.startActivity(intent);
}
});
The Intent is not passing to the other activity when the cardView is clicked.

Recycler view doesnt have current activity context, so while recycler adapter initial time you need to pass current activity of context.
check context is null or not
check DetailedView activity registered manifest or not
another war to achieve intent interface concept is there
refer this tutorial better https://www.geeksforgeeks.org/android-recyclerview/

There are multiple reasons to this crash since you have not provided the Crash logs/stacktrace.
The context provided is not an Activity context in which case you need to add the Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK to your Intent's flags.
It is possible the crash is in the DetailedView Activity due to probably a NullPointerException or it is not added to AndroidManifest.xml

This is not the right way.
First of all crate interface callback
public interface ItemClick {
void onItemClick(int position);
}
Then calling this interface method inside adapter class and passing through the constructor and finally
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (settingsItemClick!=null)
{
int pos=getAdapterPosition();
if(pos!=RecyclerView.NO_POSITION)
{
settingsItemClick.onItemClick(pos);
}
}
}
});
3.Then inside activity implements interface method.

Related

Change BottomNavigationView with a button inside a RecyclerView Item

The application has a BottomNavigationView for navigating between fragments. One of the Fragments related to the BottomNavigationView has a Fragment as a child containing a RecyclerView and each RecyclerView Item has a Button attached to it.
I would need to navigate the BottomNavigationView to another Fragment with an OnClick of the Button (Highlighted with the red) inside the RecyclerView Item. I have tried different ways but I have not gotten it to work so far.
The Click is handled inside the Adapter of the RecyclerView. (The code inside the OnClickListener is just to clarify what I am trying to do.)
#Override
public void onBindViewHolder(#NonNull LocationsViewHolder holder, int position) {
...
holder.showMarkerButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
BottomNavigationView navigation = (BottomNavigationView)v.findViewById(R.id.nav_view);
navigation.setSelectedItemId(R.id.navigation_map);
}
});
}
The easiest way is created an interface implemented by your Activity
First create an interface that i called OnItemClick :
public interface OnItemClick{
void onItemClick();
}
Following on your activity implement this interface like below :
public class MainActivity extends AppCompatActivity implements OnItemClick{
/*
rest of your code
*/
#Override
public void onItemClick() {
navigation.setSelectedItemId(R.id.navigation_map);
}
}
On your Fragment you need to pass the Activity into your Adapter
YourAdapter adapter = new YourAdapter(requireActivity());
And on your adapter you need to initialize the interface like below :
OnItemClick listener;
public YourAdapter(Activity activity) {
listener= ((MainActivity) activity);
}
And finaly to call the method on your activity just call it like below
#Override
public void onBindViewHolder(#NonNull LocationsViewHolder holder, int position) {
...
holder.showMarkerButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
listener.onItemClick();
}
});
}

How to set OnClick listener on Recycler View Adapters from within Acivity class? Or Access other RVAdapter from first Adapter?

I have a layout where I use two RecyclerViews, each with its own Adapter.
On the Activity class of the layout I have the references of the RVs and I create them there. Then I dynamically create the buttons and insert them on one of the RecyclerViews.
The current problem I'm facing is that I'm setting the onClick listener inside the adapter itself but I want to hopefully set it through the activity class.
That's because the activity class has references to all the things I need to know when an object inside the recycler view is clicked and I want them to move between the RVs when clicked. From first RV to go to second and vice versa.
To create the view inside the first adapter I use.
for (Iterator<String> it = setList.iterator();it.hasNext();)
{
String str = it.next();
Object1 o = new Object1 (str, R.drawable.testicon);
objectList.add(o);
}
firstRVAdapter.notifyDataSetChanged();
Inside my adapter I set the onclick listener inside the OnBindViewHolder as such:
#Override
public void onBindViewHolder(LeftViewHolder holder,final int position) {
holder.imageView.setImageResource(verticalLeftList.get(position).getLogo());
holder.textView.setText(verticalLeftList.get(position).getName());
holder.imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String productName =
verticalLeftList.get(position).getName().toString();
Toast.makeText(context, productName + " is selected",
Toast.LENGTH_SHORT).show();
}
});
}
Any recommendations or help how to change this to allow me to do what I want would be really appreciated. Either searching for a way to access the second adapter through the first one or a way to set the listener for each item inside RV from the activity class.
You can create a callback for your adapter to pass data back to your activity.
public interface AdapterCallback {
void itemClicked(int position);
}
see Juan's answer for example
Pass the Activity to the adapter in the constructor as a callback listener, and then, in the onClick() method call a callback on the activity.
(...) means there is more code not relevant to the answer.
In the RV Adapter class:
public MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>{
Listener listener;
public MyAdapter(Listener listener, ...){
this.listener = listener;
...
}
#Override
public void onBindViewHolder(LeftViewHolder holder,final int position) {
holder.imageView.setImageResource(verticalLeftList.get(position).getLogo());
holder.textView.setText(verticalLeftList.get(position).getName());
holder.imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String productName =
verticalLeftList.get(position).getName().toString();
Toast.makeText(context, productName + " is selected",
Toast.LENGTH_SHORT).show();
listener.onClick(productName);
}
});
}
...
public static interface Listener{
public void onRVClick(String aParamToIdWhatWasClicked);
}
}
And make the Activity implement the Listener interface and pass its instance to the RV Adapter constructor.
public class MyActivity extends AppCompatActivity implements MyAdapter.Listener {
private MyAdapter myRvAdapter;
#Override
public void onCreate(Bundle savedInstanceState){
...
myRvAdapter = new MyAapter(this, ...);
...
}
...
#Override
public void onRVClick(String what){
System.out.println(what + " was selected");
}
...
}
Note that the parameter of the onRVClick() interface method can be whatever you want. It could even be the data list item backing the selected recycler view item.

can write OnClickListener into parceable?

Hello I have a trouble with OnClickListener
View.OnClickListener listener= new View.OnClickListener()
{
#Override
public void onClick(View view)
{
Toast.makeText(Conversations.this, "click on MSG",
Toast.LENGTH_SHORT).show();
}
};
========================================================================
I Need put this listener into Fragment which will parceable.
I not parceableing listener but after readvalue is null and when click app crasher because it's reference on null object.
now I need find some methods which can use for save and read object (View.OnClickListener) if parceable or something similar.
Without this I need rebuild my project :(
Please Help me.
Thanks
_______________________________________________________--
I haven't have fragment in fragment I want all fragment put into "extra" and in other activity read from extra..
Intent i= new Intent(Conversations.this,MessagesSingleFragmentActivity.cla‌​ss); i.putExtra("Fragment1", (Parcelable) recycleMessage); startActivity(i);
and in other activity have
Intent extras = getIntent(); Fragment fragment = (Fragment) extras.getParcelableExtra("Fragment1"); fm.beginTransaction().replace(R.id.fragment_container, fragment).commit();
No you cannot pass OnClickListener as Parcelable but , if you want to observe click from one fragment to another , then you have to implement the onclick in second fragment.
FragA.java:// who have onClickListener
Runnable run;
public void setClick(Runnable run){
this.run = run;
}
view.setOnClickListener(new OnClickListener(){
public void onClick(View v){
// do something in onclick
if(run!=null){run.run();}
}
});
FragB.java:
((FragA)getParentFragment()).setClick(
new Runnable() {
#Override
public void run() {
// do something in other fragment
}
}
)
Updated:
If you want to perform something onClick of ActivityA on ActivityB , then EventBus are best options for that use Otto or EventBus by GreenBot
It is recommended to interact between fragments via Activity.. or more generally by interface which Activity conforms to.
One more thing: If you have common functionality in both fragments, maybe it is better to extract it to Activity?

Managing Multiple Fragments With ONE Interface

I have One Activity and Three Fragments. The application launches and Fragment 1 is visible. I click on a button. The Fragment communicates with the Activity through the following Interface and launches Fragment 2:
public OnClickedListener listener;
static interface OnClickedListener{
public void buttonClicked(View v);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
Activity a;
if (context instanceof Activity){
a=(Activity) context;
this.listener = (OnClickedListener)a;
}
}
...
playBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
listener.buttonClicked(v);
}
});
My MainActivity implements Fragment1.OnClickedListener, receives the data and launches Fragment 2.
Now I'm in Fragment 2. I want to click on a button and launch Fragment 3. I know that I can do that by implementing YET ANOTHER interface in Fragment 2 to then communicate to the Activity and say "Hey Launch Fragment 3". So now My Activity looks like this
MainActivity implements Fragment1.OnClickedListener,Fragment2.OnClickedListener
That's all fine but let's say that I have 20 Fragments. I don't want to have 20 interfaces implemented in my Main Activity. Is there a way to create and use a single interface to communicate between each individual Fragment and the Activity. How would that be implemented? Thank you.
You can. Create only an interface (I recommend you to create it in a separate file):
interface OnClickedListener {
void buttonClicked(Fragment fragment, View v);
}
The onButtonClicked() method accepts also a Fragment instance when a Button is clicked:
playBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// You can't use just "this", pass the class instance.
listener.buttonClicked(MyFragmentClassName.this, v);
}
});
In your Activity you will have so:
public class MainActivity extends Activity implements MainActivity.OnClickedListener {
#Override
public void buttonClicked(Fragment fragment, View v) {
// Check if the Fragment instance, or tag, or the info that you use to recognize it.
}
}
Create one nested interface in Activity or in separate file instead of nested interfaces in Fragments.

RecyclerView Onclick (call non-static method)

I've got stuck with an issue about setting an OnItemClickListener to my RecyclerView items. I tried to set a listener the way described in the RecyclerView sample of Android Studio. So a listener is set in the ViewHolder class for my RecyclerView.
public class ProgramViewHolder extends RecyclerView.ViewHolder {
protected TextView vName;
protected ImageView vProgramImage;
public ProgramViewHolder(View v) {
super(v);
vName = (TextView) v.findViewById(R.id.programName);
vProgramImage = (ImageView) v.findViewById(R.id.programImage);
v.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// HERE PROBLEM !!
MainActivity.openSettings(1);
}
});
}
}
Now I want to call a method of my MainActivity openSettings(int ) to load a fragment:
public void openSettings(int layoutId) {
settingsFragment setFrag = new settingsFragment();
Bundle information = new Bundle();
information.putInt("layoutId", layoutId);
setFrag.setArguments(information);
getFragmentManager().beginTransaction()
.replace(R.id.fragmentContainer, setFrag)
.commit();
}
But now the problem. When I try to compile, it says "Non-static method 'openSettings(int )' cannot be referenced from a static context."
I quite not understand this error. Why is it a static context? The class ProgramViewHolder ist not declared static.
And the most important part: How can I fix it? I want to set a OnClickListener to every item of RecyclerView and call a public method of MainActivity.
Thanks a lot to you, for your time spending to help me.
It's not that ProgramViewHolder is static, it's because attempting to call your activity from a static context (you aren't calling a specific instance of the activity).
What you should do is pass the activity into your recyclerViewAdapter so that you have access to it.
For example
MainActivity mainActivity;
public CustomRecyclerViewAdapter(MainActivity mainActivity) {
this.mainActivity = mainActivity;
}
And to create the recyclerViewAdapter from MainActivity
CustomRecyclerView recyclerViewAdapter = new CustomRecyclerViewAdapter(this);
recyclerViewAdapter.setAdapter(recyclerViewAdapter);
You should then be able to access your method like this
mainActivity.openSettings(1);
Let me know if you have any trouble
//Edit
Here's how you would set onClick from bindViewHolder. You want to set up any onClickListeners here due to the way RecyclerView "recycles" data. For example, if each row should perform a different action on click, you need to make sure the click listener is tied to the specific row. Creating this in onBindViewHolder ensures this. If you want an entire row to be clickable, rather than elements inside, just create an outer view that fills the entire row. Then tie the onClickListener to that.
// Replace the contents of a view (invoked by the layout manager)
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
ProgramViewHolder programViewHolder = (ProgramViewHolder) holder;
programViewHolder.vName.setOnClicklistener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mainActivity.openSettings(1);
}
});
}
if you have context of the activity containing recyclerView, then you can simply do this:
your_view_holder.v.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// HERE SOLUTION!!
((MainActivity)context).openSettings(1);
}
});
You can place this in onBindViewHolder(...)
How to get context:
Create another parameter of context in your Adapter's constructor , and pass the context from your activity once instantiating Adapter .
why pass the context:
i would recommend you to always pass context and assign it to any adapter's variable because this is something you would require every now and then while working with your adapter, so instead of using a workaround every time for context, just save it once .

Categories