Create a Generic Base Adapter?
Answering my own Question after two years.
In order to make Generic Adapter you need abstract
methods in parent class
which should be implemented by child
. So GenericAdapter
must be Abstract
and create abstract
methods for data you want to change.
I have different types of ArrayList to show in Adapter only it's model class
is different. So I decided to write a genericAdapter
. This is for recyclerview
if someOne interested
for listview. Let me know.
GenericAdapter
public abstract class GenericAdapter<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
private ArrayList<T> items;
public abstract RecyclerView.ViewHolder setViewHolder(ViewGroup parent);
public abstract void onBindData(RecyclerView.ViewHolder holder, T val);
public GenericAdapter(Context context, ArrayList<T> items){
this.context = context;
this.items = items;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder holder = setViewHolder(parent);
return holder;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
onBindData(holder,items.get(position));
}
@Override
public int getItemCount() {
return items.size();
}
public void addItems( ArrayList<T> savedCardItemz){
items = savedCardItemz;
this.notifyDataSetChanged();
}
public T getItem(int position){
return items.get(position);
}
}
And I use it like
adapter = new GenericAdapter<DataModel>(context,modelList) {
@Override
public RecyclerView.ViewHolder setViewHolder(ViewGroup parent) {
final View view = LayoutInflater.from(context).inflate(R.layout.item_view_holder, parent, false);
ItemViewHolder viewHolder = new ItemViewHolder(context, view);
return viewHolder;
}
@Override
public void onBindData(RecyclerView.ViewHolder holder1, DataModel val) {
DataModel userModel = val;
ItemViewHolder holder = (ItemViewHolder)holder1;
holder.name.setText(userModel.getName());
holder.fatherName.setText(userModel.getFatherName());
}
};
mRecyclerView.setAdapter(adapter);
RecyclerView with Search sort functionality
How to create base adapter which has type parameter that extends another class and implements an interface?
So I discovered the answer as soon as I posted the question, I'll post this in case anyone need the answer:
Change the RecyclerView.Adapter<BaseAdapter.ViewHolder>
to RecyclerView.Adapter<BaseAdapter<T>.ViewHolder>
I originally created the base adapter without the type parameter so it worked with RecyclerView.Adapter<BaseAdapter.ViewHolder>
, but after adding the type parameter, I also need to add <T>
.
Another solution is making the internal ViewHolder
static as @chRyNaN suggested.
Create Base Adapters For All Recycler View Adapters
import android.app.Activity;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
public abstract class BaseAdapter extends RecyclerView.Adapter<BaseAdapter.MyViewHolder> {
public int layout_id;
protected List<?> dataList = new ArrayList<>();
Context BASE_CONTEXT;
public View itemview;
public BaseAdapter(Context context) {
this.BASE_CONTEXT = context;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(layout_id, viewGroup, false);
return new MyViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder viewHolder, int position) {
onBindViewHold(position, dataList.get(position));
}
public abstract View getView(View view);
@Override
public int getItemCount() {
return dataList.size() == 0 ? 0 : dataList.size();
}
public abstract void onBindViewHold(int position, Object itemView);
class MyViewHolder extends RecyclerView.ViewHolder {
public MyViewHolder(@NonNull View itemView) {
super(itemView);
itemview = itemView;
getView(itemView);
}
}
public <T extends View> T bind(int id) {
return itemview.findViewById(id);
}
}
public class Adapter extends BaseAdapter {
TextView tv;
Adapter(Context context, ArrayList<String> arrayList){
super(context);
dataList=arrayList;
layout_id=R.layout.content_main2;
}
@Override
public View getView(View view) {
tv = bind(R.id.tv);
return view;
}
@Override
public void onBindViewHold( final int position, Object itemView) {
String text=(String) itemView;
Log.e("tv",tv.toString());
tv.setText(text);
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(BASE_CONTEXT, ""+position, Toast.LENGTH_SHORT).show();
}
});
}
}
Custom android adapter with generic class
You cannot keep only one instance of ViewHolder. You need to create new object everytime the convertView is null and setTag.
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View v = convertView;
ViewHolder h;
if (v == null) {
v = inflater.inflate(resources, parent, false);
h = new ViewHolder();
listener.init(v, h);
v.setTag(h);
} else {
h = (ViewHolder) v.getTag();
}
T object = (T) getItem(position);
listener.execute(object, h);
return v;
}
Type Mismatch with Kotlin Generic Adapter
that's because you're mixing type T
and Any
, try this:
BaseViewHolder
abstract class BaseViewHolder<T>(override val containerView: View) :
RecyclerView.ViewHolder(containerView),
LayoutContainer
BaseViewAdapter
abstract class BaseAdapter<T>(
@LayoutRes open val layoutId: Int,
private val dataList: ArrayList<T>?
) : RecyclerView.Adapter<BaseViewHolder<T>>() {
abstract fun setViewHolder(parent: ViewGroup): BaseViewHolder<T>
abstract fun bind(containerView: View, item: T)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<T> {
return setViewHolder(parent)
}
override fun onBindViewHolder(holder: BaseViewHolder<T>, position: Int) {
bind(holder.containerView, dataList!![position])
}
override fun getItemCount(): Int = dataList!!.size
override fun getItemViewType(position: Int): Int =
if (dataList!!.size == 0) IS_EMPTY else IS_NOT_EMPTY
}
How to use databinding with generics in an adapter class?
The error suggests, that you need to cast the item to type Item
instead of I
. This makes sense because your layout declares the variable with type Item
. The ViewHolder however provides an object of an unconstrained type I
, which clearly doesn't conform to Item
.
Instead of a cast, you can constrain the generic type I
to be a subtype of Item
:
class ItemAdapter<I: Item>(...) {
...
inner class ItemViewHolder<I: Item>(...) {...}
}
This should make the assignment dataBinding.item = item
valid.
Somewhat unrelated: I think it's unnecessary to redeclare the generic type I
for the inner class. You should be able to just use the I
of the outer class ItemAdapter<I: Item>
.
I have to admit I don't fully understand your code, so I may be missing something. For your reference, here is a very similar implementation of an adapter with data binding I use in my project. It allows configurable layout. The only thing it assumes is a binding variable called model
.
class DataBindingListAdapter<T>(@LayoutRes private val itemLayout: Int, diffCallback: DiffUtil.ItemCallback<T>) : ListAdapter<T, DataBindingListAdapter<T>.ViewHolder>(diffCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = DataBindingUtil.inflate<ViewDataBinding>(layoutInflater, itemLayout, parent, false)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(getItem(position))
}
inner class ViewHolder(private val binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(model: T?) {
binding.setVariable(BR.model, model)
binding.executePendingBindings()
}
}
}
Related Topics
React Native Android Duplicate File Error When Generating APK
Firestorepagingadapter Not Receiving Realtime Updates
Android Add Image to Webview from a Drawable
Use Dll Files in Android Application
Android Stock Browser Not Respecting CSS Overflow
Android Browser Bug? Div Overflow Scrolling
How Many Activities Vs Fragments
Fragmentpageradapter Getitem Is Not Called
Air 3 Native Extensions for Android - Can I/How to Include 3Rd Party Libraries
Open Google Maps Through Intent for Specific Location in Android
Android - Choose File Button in Webview
How to Access Files Under Assets Folder of Other APK'S
Android Webview Hardware Acceleration Artefact Workarounds
Using Multiple Text Colors in Android's Textview [ HTML.Fromhtml() ]
Android Custom Url to Open App Like in iOS
How to Access Adb in Os X Through Terminal, "Command Not Found"