I use DataBindings and RecyclerView in my project.
I have a base adapter for RecyclerView. It looks like this
public abstract class BaseAdapter<T extends ViewDataBinding> extends RecyclerView.Adapter<BaseAdapter.ViewHolder> {
public BaseAdapter() {}
public class ViewHolder extends RecyclerView.ViewHolder {
public T binding;
public ViewHolder(View view) {
super(view);
binding = DataBindingUtil.bind(view);
}
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
... code ...
}
}
ViewHolder extended classes differs only binding field type.
After the implementation of the extended BaseAdapter class:
public class BaseAdapterExtended extends BaseAdapter<BaseAdapterExtendedBinding> {
public BaseAdapterExtended(ArrayList<ItemModel> itemModels) {
super();
mData = itemModels;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
return new ViewHolder(BaseAdapterExtendedBinding.inflate(inflater, parent, false).getRoot());
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
}
#Override
protected View getItemRootView(ViewHolder holder) {
return holder.binding.item;
}
#Override
public int getItemCount() {
return mData.size();
}
}
i am got next compilation error:
error: BaseAdapterExtended is not abstract and does not override abstract method onBindViewHolder(BaseAdapter.ViewHolder,int) in Adapter
Seems like BaseAdapterExtended hasn't this method, but he exists.
If I change
public void onBindViewHolder(ViewHolder holder, int position)
to
public void onBindViewHolder(BaseAdapter.ViewHolder holder, int position)
Projections compiled fine, but type binding will be ViewDataBinding instead BaseAdapterExtendedBinding. Why is this happening? Any ideas?
In my case I had forgotten to parameterize my superclass. When creating the class I hadn't yet created the ViewHolder, and it was very permissive except for the error on that method. I.e.:
public class FooAdapter extends RecyclerView.Adapter {
Had to be changed to
public class FooAdapter extends RecyclerView.Adapter<FooAdapter.FooViewHolder> {
This needed to be done anyways, but the only compiler error I got was in onBindViewHolder.
in this line:
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
}
replace ViewHolder with BaseAdapterExtended.ViewHolder
I just found out the reason to this weird issue. This is happening in my project too but only for adapters that are parametrized, like yours is. All other adapters saw the BindViewHolder() method without needing to explicitly specify the ViewHolder in the class. The solution is to parametrize the ViewHolder class with any random param type, this looks like it's a bug.
public abstract class BaseAdapter<T extends ViewDataBinding> extends RecyclerView.Adapter<BaseAdapter.ViewHolder> {
public BaseAdapter() {}
public class ViewHolder<RandomTypeNotUsed> extends RecyclerView.ViewHolder {
public T binding;
public ViewHolder(View view) {
super(view);
binding = DataBindingUtil.bind(view);
}
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
... code ...
}
}
Works fine for me!
//like is my imageview
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int i) {
MyViewHolder myViewHolder1 = (MyViewHolder)viewHolder;
myViewHolder1.like.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context, "yay" + i, Toast.LENGTH_SHORT ).show();
}
});
}
Related
I saw many methods to write Recyclerview. But I do not know what is the best practice way in terms of performance.
I have two methods to write a Recyclerview, are they the same or is there in difference?
First method is to write it in separate Adapter class
Adapter.java
public class Adapter extends RecyclerView.Adapter<Adapter.MyViewHolder> {
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
return null;
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder myViewHolder, int i) {
}
#Override
public int getItemCount() {
return 0;
}
class MyViewHolder extends RecyclerView.ViewHolder{
public MyViewHolder(#NonNull View itemView) {
super(itemView);
}
}
}
Second method is to write it like this inside the MainActivity or Fragment
recyclerView.setAdapter(new RecyclerView.Adapter() {
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
return null;
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder viewHolder, int i) {
}
#Override
public int getItemCount() {
return 0;
}
});
}
public class MyViewHolder extends RecyclerView.ViewHolder{
public MyViewHolder(#NonNull View itemView) {
super(itemView);
}
}
The adapter should be implemented as a separated class, because it makes re-using it easier:
public class YourAdapter extends RecyclerView.Adapter<Adapter.MyViewHolder> {
private ArrayList<YourModel> list = new ArrayList();
public YourAdapter(ArrayList<YourModel> list){
this.list = list;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
//return the viewholder
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder myViewHolder, int i) {
//deal with data
}
#Override
public int getItemCount() {
//return the list number
}
class MyViewHolder extends RecyclerView.ViewHolder{
public MyViewHolder(#NonNull View itemView) {
super(itemView);
//bind the views
}
}
}
Than in your Activity/Fragment you can use it like this :
//after you have initialized recyclerview and added the layoutmanager
//prepare the list for the adapter
recyclerView.setAdapter(new YourAdapter(yourList));
This way you can reuse it in more than one Activity/Fragment. This pattern of reusable code should be preferred because you don't have to create the classes multiple times as anonymous classes - if needed.
the best way is to set adapter class outside main class as your explain just use your first class
I'm trying to develop a project in accordance with MVP standarts. In the guide i followed, author created separate ViewHolder class. I tried to do the same, but Adapter refuses to work with separate ViewHolder.
There is 2 errors
Cannot resolve symbol 'LessonCardView'
'onCreateViewHolder(ViewGroup, int)' in RVAdapter clashes with 'onCreateViewHolder(ViewGroup, int)' in 'android.support.v7.widget.RecyclerView.Adapter'; attempting to use incompatible return type
RVAdapter.java
public class RVAdapter extends RecyclerView.Adapter<RVAdapter.LessonCardViewHolder> {
private String[] mDataset;
public RVAdapter(String[] dataset) {
mDataset = dataset;
}
#Override
public LessonCardViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new LessonCardViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.lessons_item_card, parent, false));
}
#Override
public void onBindViewHolder(LessonCardViewHolder holder, int position) {
}
#Override
public int getItemCount() {
return mDataset.length;
}
}
LessonCardViewHolcer.java
public class LessonCardViewHolder extends RecyclerView.ViewHolder implements LessonCardView {
private final TextView lessonCardText;
public LessonCardViewHolder(View itemView) {
super(itemView);
lessonCardText = (TextView) itemView.findViewById(R.id.lesson_card_view);
}
#Override
public void setLessonCardText(String text) {
lessonCardText.setText(text);
}
}
I created subclass ViewHolder that inherited from LessonCardView in RVAdapter. Errors disappeared. But i'm not sure if this the right way. If it works for someone else, then i'm doing something wrong.
Change your adapter declaration from this
public class RVAdapter extends RecyclerView.Adapter<RVAdapter.LessonCardViewHolder> {
to this
// import here your view holder
public class RVAdapter extends RecyclerView.Adapter<LessonCardViewHolder> {
It looks like from how you're providing the snippets that these classes are in different files, or not correctly nested within the same file.
Have you tried using RecyclerView.Adapter<LessonCardViewHolder> rather than RecyclerView.Adapter<RVAdapter.LessonCardViewHolder>?
LessonCardViewHolder should be a nested class in RVAdapter
Here is the complete solution - Recyclerview Adapter class example
public class IAdapter extends RecyclerView.Adapter<IAdapter.ViewHolder> {
Context context;
ArrayList<Model> modelList;
public ImagesAdapter(Context context,ArrayList<Model> modelList) {
this.context=context;
this.modelList=modelList;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_items, parent, false);
return new ViewHolderImages(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Model model=photo.get(position);
userViewHolder.textView.setText(model.getTitle());
}
public class ViewHolder extends RecyclerView.ViewHolder{
TextView textView;
public ViewHolderImages(View itemView) {
super(itemView);
textView=(TextView)itemView.findViewById(R.id.textView);
}
}
#Override
public int getItemCount() {
return modelList.size();
}
}
After I changed the parameter of onBindViewHolder,it turned gray,and not be called,why? Here is my adapter:
public class Myadapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
private List<String> lists;
private OnItemClickListener onItemClickListener;
public Myadapter(Context context, List<String> lists) {
this.context = context;
this.lists = lists;
}
public interface OnItemClickListener {
void onItemClick(View view, int postion);
void onItemLongClick(View view, int postion);
}
public void setOnItemClickListener(OnItemClickListener listener) {
this.onItemClickListener = listener;
}
#Override
public void onBindViewHolder(final myViewHolder holder, int position) {
holder.textView.setText(lists.get(position));
if (onItemClickListener != null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int postion = holder.getLayoutPosition();//得到当前点击item的位置postion
onItemClickListener.onItemClick(holder.itemView, postion);
}
});
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
int postion = holder.getLayoutPosition();
onItemClickListener.onItemLongClick(holder.itemView, postion);
return true;
}
});
}
}
#Override
public int getItemCount() {
return lists.size();
}
#Override
public myViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(context).inflate(R.layout.item,parent,false);
myViewHolder viewHolder = new myViewHolder(itemView);
return viewHolder;
}
public class myViewHolder extends RecyclerView.ViewHolder{
TextView textView;
public myViewHolder(View itemView){
super(itemView);
textView =(TextView)itemView.findViewById(R.id.text);
}
}
}
It says Myadapter must either be declared abstract of implement abstract method onBindViewHolder(VH,int) in "Adapter"
Since you are trying to use your own ViewHolder for this adapter you need to use it as the type when extending RecyclerView.Adapter.
Change:
public class Myadapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
To:
public class Myadapter extends RecyclerView.Adapter<myViewHolder> {
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
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;
}
});
}
. . .
}