Recycle Item Click issue and never go into function - android

I'm new on Android material design and wanna use Recycle View instead of List View but having problem on implement OnClickListener.
I find out that RecyclerView.Adapter a bit different from ListView.Adapter.
first I impelement OnClick listener in onBindViewHolder but it returns wrong item numbers and lead to out of-bound after some removing.
#Override
public void onBindViewHolder(PersonViewHolder personViewHolder, int i) {
final int index = i ;
personViewHolder.cv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
... items.get(index).gettext();
}
so I find out that I should implement OnClikListener in my ViewHolder class as this link.
but in this case never inter to OnClick.
public static class PersonViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
#Override
public void onClick(View v) {
Log.i("log","position="+getAdapterPosition());
}
}
public CardViewAdapter(List<MessageTO> persons) {
this.items = persons;
}
#Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
#Override
public PersonViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.deposite_card_view, viewGroup, false);
PersonViewHolder pvh = new PersonViewHolder(v);
return pvh;
}
#Override
public void onBindViewHolder(PersonViewHolder personViewHolder, int i) {
...
}
also I find out that I should do my Initializing item values all in onBindViewHolder is it right or not? I am very confused.

First you need to set the onclicklistener as shown below. Then it should work.
public static class PersonViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public ViewHolder(View itemView) {
super(itemView);
.
.
.
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
Log.i("log","position="+getAdapterPosition());
}
}

You need to call viewHolder.itemView.setOnClickListener(viewHolder) somewhere to make it work

Related

itemView.getTag() returns -1

I am using RecyclerView and I want to view the the data of list item that I click on. I'm using itemView.getTag() to get the value of index and typecasting it to my CustomAdapter.
I tried various ways but not to help. please help me.
Here's my code:
public class DonorAdapter extends RecyclerView.Adapter<DonorAdapter.ViewHolder> {
ArrayList<Donor> donorsList;
ItemSelected activity;
public interface ItemSelected{
void onItemClicked(int index);
}
public DonorAdapter(Context context, ArrayList<Donor> list){
activity = (ItemSelected) context;
donorsList = list;
}
public class ViewHolder extends RecyclerView.ViewHolder
{
ImageView ivDonorGender;
TextView tvListName;
TextView tvBloodGroup;
public ViewHolder(#NonNull final View itemView) {
super(itemView);
ivDonorGender = itemView.findViewById(R.id.ivDonorGender);
tvListName = itemView.findViewById(R.id.tvListName);
tvBloodGroup = itemView.findViewById(R.id.tvListBloodGroup);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
activity.onItemClicked(donorsList.indexOf((Donor) itemView.getTag()));
}
});
}
}
#NonNull
#Override
public DonorAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.donors_list, parent, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(#NonNull DonorAdapter.ViewHolder holder, int position) {
holder.tvListName.setText(donorsList.get(position).getName());
holder.tvBloodGroup.setText(donorsList.get(position).getSurname());
}
}
#Override
public int getItemCount() {
return donorsList.size();
}
}
I am new to android so pardon me if I can't explain properly
Here's the problematic part
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
activity.onItemClicked(donorsList.indexOf((Donor)
itemView.getTag()));
}
I think you need to set the tag for each recycled item in onBindViewHolder
#Override
public void onBindViewHolder(#NonNull DonorAdapter.ViewHolder holder, int position) {
holder.tvListName.setText(donorsList.get(position).getName());
holder.tvBloodGroup.setText(donorsList.get(position).getSurname());
holder.itemView.setTag(donorsList.get(position)); // change here
}
}

RecyclerView OnItemclick not working properly

I have a recycler view and I am implementing OnClicklistener inside it. Basically , I have an adapter class called actressadapter and a viewholder class MyViewHolder.I am implementing OnClickListener inside viewholder class to initiate another activity via intent method. My basic data is inside a class called actress which has three variables name,country(both String) and an Id(UUID). I am providing this data that is of actresses to my adapter.Next activity is just displaying the name of actress like abc ,def etc that it retrieves . The fault is that it shows name of only one actress after clicking. For instance if it shows abc ,then for each click it will show abc.Don't know why is this happening because as per code I am passing actressname as an extra .
public class actressadapter extends RecyclerView.Adapter <actressadapter.MyViewHolder> {
private List<Actress>al;
private Actress actress,mActress;
public static final String str="shivam.panwar.actressdetails.actressadapter.str";
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView naam, desh;
public MyViewHolder(View view) {
super(view);
view.setOnClickListener(this);
naam = (TextView) view.findViewById(R.id.name);
desh= (TextView) view.findViewById(R.id.country);
}
#Override
public void onClick(View v) {
Toast.makeText(v.getContext(),"Clicked",Toast.LENGTH_SHORT).show();
Intent intent=new Intent(v.getContext(),Actressview.class);
intent.putExtra(str,actress.getName());
v.getContext().startActivity(intent);
}
public void bindactress(Actress mActress) {
naam.setText(mActress.getName());
desh.setText(mActress.getCountry());
}
}
public actressadapter(List<Actress> al) {
this.al = al;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.actress_list_row, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
actress =al.get(position);
holder.bindactress(actress);
}
#Override
public int getItemCount() {
return al.size();
}
}
If required any further assist about code please comment.
try this way hope it works...
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
actress =al.get(position);
holder.bindactress(actress);
holder.naam.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context,holder.naam.getText().toString(), Toast.LENGTH_SHORT).show();
Intent intent = new Intent(context,Actressview.class);
intent.putExtra(str,holder.naam.getText().toString());
context.startActivity(intent);
}
});
}
The best way to use the method getLayoutPosition() of adapter class to get the selected item(position).
You have to update your code for better result. Replace your existing code with that.
public class actressadapter extends RecyclerView.Adapter <actressadapter.MyViewHolder> {
private List<Actress>al;
private Actress actress,mActress;
private int itemPosition; // change
public static final String str="shivam.panwar.actressdetails.actressadapter.str";
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView naam, desh;
public MyViewHolder(View view) {
super(view);
view.setOnClickListener(this);
naam = (TextView) view.findViewById(R.id.name);
desh= (TextView) view.findViewById(R.id.country);
}
#Override
public void onClick(View v) {
itemPosition = getLayoutPosition(); // change
Toast.makeText(v.getContext(),"Clicked",Toast.LENGTH_SHORT).show();
Intent intent=new Intent(v.getContext(),Actressview.class);
intent.putExtra(str,al.get(itemPosition).getName()); // change
v.getContext().startActivity(intent);
}
public void bindactress(Actress mActress) {
naam.setText(mActress.getName());
desh.setText(mActress.getCountry());
}
}
public actressadapter(List<Actress> al) {
this.al = al;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.actress_list_row, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
actress =al.get(position);
holder.bindactress(actress);
}
#Override
public int getItemCount() {
return al.size();
}
}
Hope it will work..
your issue is that you made actress a variable of the Adapte, and it should be of the Holder.
To fix it:
Delete the line:
private Actress actress,mActress;
Change the onBindViewHolder method to:
holder.bindactress(al.get(position))
And make replace your holder class with that:
// holder HAVE TO be static. It's WRONG not doing it static
public static class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView naam, desh;
Actress actress;
public MyViewHolder(View view) {
super(view);
view.setOnClickListener(this);
naam = (TextView) view.findViewById(R.id.name);
desh= (TextView) view.findViewById(R.id.country);
}
#Override
public void onClick(View v) {
Toast.makeText(v.getContext(),"Clicked",Toast.LENGTH_SHORT).show();
Intent intent=new Intent(v.getContext(),Actressview.class);
intent.putExtra(str,actress.getName());
v.getContext().startActivity(intent);
}
public void bindactress(Actress mActress) {
this.actress = mActress;
naam.setText(mActress.getName());
desh.setText(mActress.getCountry());
}
}

Android : is correct put setOnclickListener or or setOnLongClickListener in onBindViewHolder?

Can i put setOnclickListener or or setOnLongClickListener in onBindViewHolder?
No problem in this method onBindViewHolder to write? (Is it wise or not?)
Or better in ViewHolder to write?
public void onBindViewHolder(ViewHolder holder, int position) {
myBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//...
}
}); }
This method is a bad influence on the speed of the RecyclerView list?
Add it on your onCreateViewHolder method so that you won't churn listener objects. You should use vh.getAdapterPosition to map it back to your data.
ViewHolders are basically caches of your View objects and inner classe of the RecyclerView.
Since RecyclerView.Adapter is abstract you will have to implement these three methods:
public VH onCreateViewHolder(ViewGroup parent, int viewType)
public void onBindViewHolder(VH holder, int position)
public int getItemCount()
you can use an RecyclerView.OnItemTouchListener in combination with gesture detection to identify those events.
You can add listeners in your custom adapter implementation. It will be something like:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
public interface OnItemClickListener {
public void onItemClicked(int position);
}
public interface OnItemLongClickListener {
public boolean onItemLongClicked(int position);
}
private Fragment mFragment;
public static class ViewHolder extends RecyclerView.ViewHolder {
public View v;
public ViewHolder(View v) {
super(v);
this.v = v;
}
}
public RecyclerViewAdapter(Fragment fragment) {
mFragment = fragment;
}
#Override
public void onBindViewHolder(ViewHolder holder, final int position) {
holder.v.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mFragment.onItemClicked(position);
}
});
holder.v.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
mFragment.onItemLongClicked(position);
return true;
}
});
}
. . .
}

RecyclerView data are multiple modified/displayed

I've a small problem with my RecyclerView. It's well filled by my adapter with some TextViews, an ImageView and some buttons. When there's an OnClick-Event on one of the buttons it modifies a TextView - so far so good but when I'm scrolling some items further another RecyclerView-item is also modified and has the value of the originally modified one.
I tried already to move the setOnClickListener into my ViewHolder but the result was the same.
May be you can help me.
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
// some vars .... and a constructor
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(mContext).inflate(R.layout.recyclerview_item, viewGroup, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final ViewHolder viewHolder, final int i) {
// ...
viewHolder.myTextView.setText("clear");
viewHolder.myButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
viewHolder.myTextView.setText("modified");
}
});
// ...
}
#Override
public int getItemCount() {
return mProducts.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView productMultibuy;
private Button productAddToShoppingList;
// ...
public ViewHolder(View itemView) {
super(itemView);
myTextView = (TextView) itemView.findViewById(R.id.my_textview);
myButton = (Button) itemView.findViewById(R.id.my_button);
// ...
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
return false;
}
});
}
}
}
Reading from here.
RecyclerView, just the same as ListView and GridView, reuses views whenever possible. That means while you scroll, views that fall off the top are used for the views on the bottom, etc. This greatly improves the memory efficiency and scroll performance. This means if you don't reset all of the state on a new item, you'll see state left over from the last time this view was used.
always reset all the of the state
thanks, but I solved the problem with setTag() and getTag()
public class MyAdapter extends RecyclerView.Adapter {
// some vars .... and a constructor
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(mContext).inflate(R.layout.recyclerview_item, viewGroup, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final ViewHolder viewHolder, final int i) {
// ...
}
#Override
public int getItemCount() {
return mProducts.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView productMultibuy;
private Button productAddToShoppingList;
// ...
public ViewHolder(View itemView) {
super(itemView);
myTextView = (TextView) itemView.findViewById(R.id.my_textview);
myTextView.setTag(this);
myButton = (Button) itemView.findViewById(R.id.my_button);
myButton.setTag(this);
// ...
myButton.getTag();
myButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
myTextView.getTag();
myTextView.setText(String.valueOf(amount));
}
}
});
}
}
}

Use same Recycler Adapter for inflating different activities

I have the following adapter
public class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder>{
List<String> list;
int id;
Context context;
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view= LayoutInflater.from(parent.getContext()).inflate(id,parent,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
holder.textView.setText(list.get(position));
holder.textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Handler handler=new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
Intent intent = new Intent(context, BESyllabus.class);
context.startActivity(intent);
}
},500);
}
});
}
#Override
public int getItemCount() {
return list.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder{
public TextView textView;
public CardView cardView;
public ViewHolder(View v){
super(v);
textView=(TextView)v.findViewById(R.id.text);
cardView=(CardView)v.findViewById(R.id.card_view);
}
}
public CardAdapter(List<String> list, int id,Context context){
this.list=list;
this.id=id;
this.context=context;
}
}
I use the same layout file which has a recyclerView which uses the above adapter,id is the resource id for layout file which i use as rows for recycler view`
<?xml version="1.0" encoding="utf-8"?>
<TextView
android:id="#+id/text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#000000"
android:alpha="0.87"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:textSize="35dp" />
What i want to do is inflate multiple activities using the same row structure using the same adapter. It works fine while displaying the rows but the same onClickListener is used in every activity relaunching the same activity every time i click. Is there a way to use the same adapter where i can assign listeners based on the activity.Or should i create new adapter for every activity? I am new to android development so any help will be appreciated.Thanks in advance.
Use the interface :
public class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder>{
private IOnItemClickListener mListener;
public CardAdapter(IOnItemClickListener mListener) {
this.mListener = mListener;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view= LayoutInflater.from(parent.getContext()).inflate(id,parent,false);
return new ViewHolder(v, new CardAdapter.ViewHolder.IMyViewHolderClicks() {
public void onClick(View v, int position) {
mListener.onItemClick(v, position);
};
});
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView textView;
public CardView cardView;
public IMyViewHolderClicks mListener;
public ViewHolder(View v, IMyViewHolderClicks listener) {
super(itemView);
mListener = listener;
textView=(TextView)v.findViewById(R.id.text);
cardView=(CardView)v.findViewById(R.id.card_view);
}
#Override
public void onClick(View v) {
mListener.onClick(v, getPosition());
}
public interface IMyViewHolderClicks {
public void onClick(View v, int position);
}
}
}
public interface IOnItemClickListener {
public void onItemClick(View v, int position);
}
You should pass an OnClickListener to the CardAdapter (on its constructor maybe) and implement it on the activity working with this Adapter.
public class ActivityX extends Activity implements View.OnClickListener {
CardAdapter adapter;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
adapter = new CardAdapter(this)
}
public void onClick(View v) {
// Handle click here
String string = (String) v.getTag();
}
}
Your Adapter may then look like this:
public class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder> {
View.OnClickListener onClickListener;
public CardAdapter(View.OnClickListener onClickListener) {
this.onClickListener = onClickListener;
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
// Saving object from list at given position in View tag
holder.setTag(list.get(position));
holder.textView.setText(list.get(position));
holder.textView.setOnClickListener(onClickListener);
}
}
You can pass the listener as a constructor argument to the Adapter
In this answer there's an implementation of a onItemClickListener for a recycler view. You could move the code from your onClickListener to a diferent onItemClickListener for each diferent activity you need.
First of all, what is a reason to use handler delay in setOnClickListener? This code will lead to an NullPointerException in cases when context was destroyed before.
On the subject of the question you could pass onClickListener via constructor as in previous answers, pass only Class variable of target activity, make broadcast event. It depends on your needs. But the most appropriate in most cases i think is not make onClickListener inside adapter, setting onItemClickListener of recycler view instead (as #tinuviel answer). In this case pressed state of recycle view item will be animated automatically

Categories

Resources