Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
How to work with adapters, RecyclerView and ListView

Overview

This snippet is focus on how to create a RecyclerAdapter, for so please refer to the files:

  1. SomeFragment.java
  2. CustomRecyclerAdapter.java

There you will find details. In case you need you can see the classic ListView adapter in the file ListViewAdapter.java by example if you need to create a dropdown a.k.a AndroidSpinner. If you are looking to create an Android spinner then this tutorial should help you.

Instructions

Learning how to use the adapter for the RecyclerView is very important, is an optimized adapter in comparison to the previous for the ListView. This gist assume you have an xml layout for your row, if you haven't create it yet, do it now

  1. Go to the CustomRecyclerAdapter.java and adapt what you need.
  2. Then you have to set the adapter to the RecyclerView, you can see how to do that in the SomeFragment.java file

Please pay close attention to what is marked as important inside the CustomRecyclerAdapter, it will spare you some headaches.

//Create the inner class before extending it, yes obvious, but sometimes can be forgotten
public class CustomRecyclerAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {
//Sometimes you can have your set of data as empty but initialized and then update it using an update method
//This is usefull when you want to do an http request, set the adapter empty then when the AsyncTask is done, refresh it
private List<YourObject> mObjects = new ArrayList();
//There is no constructor matching the super here, so create your own with what ever you need
public CustomAdapter() {
}
//Maybe you need just to pass the id, then make the query inside the constructor
public CustomAdapter(long id) {
mObjects = YourObject.someQuery(id);
}
//You can pass the data from the View
public CustomAdapter(List<YourObject> mObjects) {
this.mObjects = mObjects;
}
//This will inflate your view
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//The RecyclerView is very interesting because it will literrally recycle the view, if you put a log here, and in onBindViewHolder
//you will notice this only happen some times. RecyclerView create an optimized pool of view, if the view is available there
//this will not happen then onBindViewHolder will set the data to the view directly
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_custom, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
YourObject object = mObjects.get(position);
//This is the view you set in the subclass
holder.name.setText(object.getName());
//Lets change the text color on click
holder.name.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/*
VERY IMPORTANT
*/
//Your data (object) neither the position (in the method argument) can't be final
//final data or position will create inconsistencies in the list
//Since the view is recycled, if the data or position is final it will not be redefined when
//making some rows have data belonging to other rows
//The correct way to access data inside an inner implementation of an interface such as a click listener
//is not strugling with the recycler logic, but using on your advantage
//You have to use the holder and get the position from there
YourObject auxObect = mObjects.get(holder.getAdapterPosition());
if (auxObject.isColored()) {
v.setTextColor(ContextCompat(v.getContext(), getColor(R.color.colorAccent))
} else {
v.setTextColor(ContextCompat(v.getContext(), getColor(android.R.color.black))
}
}
});
//You don't need the context, you can get it from any view
ImageView imageView = holder.photo;
Picasso.with(imageView.getContext()).load(object.getUrl()).into(imageView);
}
/*
VERY IMPORTANT
*/
//Always start with this method, if return 0; no mather everything else is fine, there will be nothing in the view
@Override
public int getItemCount() {
return mObject.size();
}
//This inner class have to be created first, so the parent class can extend to it
//A ViewHolder is the representation of your xml layout R.layout.list_item_custom
public static class ViewHolder extends RecyclerView.ViewHolder {
//Every variable here should be the representation of each xml element in the layout of the row
private TextView name;
private ImageView photo;
ViewHolder(View view) {
super(view);
//You can find yout views because the argument view is the inflated layout in the onCreateViewHolder
name = (TextView) view.findViewById(R.id.itemNameId);
photo = (ImageView) view.findViewById(R.id.itemPhotoId);
}
}
}
//Dont forget to set the adapter to the RecyclerView and mainly, RecyclerViews need a LayoutManager so you need to do that also
//Here Im passing a custom model, but you can use a String
public class CustomAdapter extends ArrayAdapter<YourObject> {
//Most of the time this is your constructor, otherwise maybe you need the YourObject[]
public AssignationAdapter(Context context, int resource, List<c> objects) {
super(context, resource, objects);
//If you create a global variable int resource, and here this.resource = resource, you can change the resource programatically by the instatiation
}
//You are going to use this subclass as a way to access your views as variables
private class ViewChildHolder {
//Make sure you have 1 variable for each view you want to manipulate, this view could be a LinearLayout with a TV and a IV
TextView objectName;
ImageView objectPhoto;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
ViewChildHolder holder;
//This will inflate your view using the subclass above
if (convertView == null) {
//You are passing your resource again here, cause there is no resource global variable
convertView = inflater.inflate(R.layout.list_item_custom, parent, false);
holder = new ViewChildHolder();
//Here you can find the views you want to manipulate
holder.objectName = (TextView) convertView.findViewById(R.id.objectNameId);
//TODO find the IV holder holder.objectPhoto = ...
convertView.setTag(holder);
} else {
holder = (ViewChildHolder) convertView.getTag();
}
//get the item by posisiont and set the name to the TV
holder.objectName.setText(getItem(position).getName());
return convertView;
}
/*If you are working with a spinner then the this method will change the dropdown elements appearance. The previous
getView method will be the view in the spinner. You can do here the same that is done in getView*/
/*@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return convertView;
}*/
@Override
public long getItemId(int position) {
//Does your object has an Id of some sort, then override this and you will get the Id in the itemClickListener by example
return getItem(position).getid();
}
}
//Dont forget to set the adapter later to your view
public class SomeFragment {
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//The xml is a RecyclerView
RecyclerView recyclerView = (RecyclerView) view;
/*Layout Managers Example*/
//Linear Vertical by default
LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
//Linear but horizontal (the third boolean param can invert the order, the second can be Vertical)
LinearLayoutManager horizontalManager = new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false);
//Grid
GridLayoutManager gridLayoutManager = new GridLayoutManager(context, 2);
//You can also set it to the the Recycler anonymously
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
//Calculating the size of the row is a heavy operation, if you know all the rows have the same size set this to true, for better performance
recyclerView.setHasFixedSize(true);
//If you dont set the adapter then nothing will be shown
SomeAdapter adapter = new SomeAdapter();
recyclerView.setAdapter(adapter);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment