Google I/O this week brought a lot of exciting news about Android, and we probably need quite some time to get used to what Android L is bringing.
I’ve been playing with RecyclerView these days, and will give you a little presentation of what I discovered so far.
RecyclerView: What it is?
The RecyclerView is a new ViewGroup that is prepared to render any adapter-based view in a similar way. It is supossed to be the successor of ListView and GridView, and it can be found in the latest support-v7 version.
The RecyclerView has been developed with extensibility in mind, so it is possible to create any kind of layout you can think of, but not without a little pain-in-the-ass dose. This is Android, so things are never easy.
If you want to use a RecyclerView, you will need to feel comfortable with three elements:
– RecyclerView.Adapter
– LayoutManager
– ItemAnimator
RecyclerView.Adapter
RecyclerView includes a new kind of adapter. It’s a similar approach to the ones you already used, but with some peculiarities, such as a required ViewHolder. You will have to override two main methods: one to inflate the view and its view holder, and another one to bind data to the view. The good thing about this is that first method is called only when we really need to create a new view. No need to check if it’s being recycled.
[java]
public class MyRecyclerAdapter extends RecyclerView.Adapter<MyRecyclerAdapter.ViewHolder> {
private List<ViewModel> items;
private int itemLayout;
public MyRecyclerAdapter(List<ViewModel> items, int itemLayout) {
this.items = items;
this.itemLayout = itemLayout;
}
@Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(itemLayout, parent, false);
return new ViewHolder(v);
}
@Override public void onBindViewHolder(ViewHolder holder, int position) {
ViewModel item = items.get(position);
holder.text.setText(item.getText());
holder.image.setImageBitmap(null);
Picasso.with(holder.image.getContext()).cancelRequest(holder.image);
Picasso.with(holder.image.getContext()).load(item.getImage()).into(holder.image);
holder.itemView.setTag(item);
}
@Override public int getItemCount() {
return items.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public ImageView image;
public TextView text;
public ViewHolder(View itemView) {
super(itemView);
image = (ImageView) itemView.findViewById(R.id.image);
text = (TextView) itemView.findViewById(R.id.text);
}
}
}
[/java]
That’s a simple Adapter. But things start to get complicated. There isn’t (or a least I didn’t found) a onItemClickListener on RecyclerView. So the adapter will be a good candidate to handle the events.
If you want to add or remove items from the adapter, you will need to explicitly inform to the adapter. That’s a bit different from the former notifyDataSetChanged():
[java]
public void add(ViewModel item, int position) {
items.add(position, item);
notifyItemInserted(position);
}
public void remove(ViewModel item) {
int position = items.indexOf(item);
items.remove(position);
notifyItemRemoved(position);
}
[/java]
LayoutManager
This is the class that will decide in which part of the screen the views are placed. But that’s only one of its many responsibilities. It must be able to manage scrolling and recycling among others.
There’s only one implemented class of this LayoutManager. It’s called LinearLayoutManager, and it is above 1500 lines of code, only for you to understand the complexity. This manager is able to simulate a ListView (both vertical and horizontal), without headers or footers.
Subclassing LayoutManager is not for rookies at all, and we will have to rely on community to achieve RecyclerView full potential. Along with the example, I will be uploading in short time an implementation for GridView.
I think the key behind this is to create a BaseLayoutManager from LinearLayoutManager code and extend it from here. Probably the final version of support-v7 will come with more and better implementations.
ItemAnimator
ItemAnimator will animate ViewGroup modifications that are notified to adapter. Basically it will automatically animate adding and removing items. That’s not an easy class either, and we find a DefaultItemAnimator that works quite well.
RecyclerView setup
So, in the end, if you want to initialize a working RecyclerView, you will need to do something like this:
[java]
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.list);
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(new MyRecyclerAdapter(createMockList(), R.layout.item));
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setItemAnimator(new DefaultItemAnimator());
[/java]
setHasFixedSize() is used to let the RecyclerView that its size will keep the same. This information will be used to optimize itself.
Conclusion
RecyclerView is indeed a powerful view, and its limits will be more in the part of the developer that the view itself. The learning curve may be hard, but I’m sure that Android community will soon release awesome implementations of LayoutManager.
I’m creating a github repository, where you can find this example. It will serve as the basis for an extension library I’m planning to create. You will be able to test a GridView implementation. Any feedback will be welcomed.
Sounds excellent. Looking forward to see your example. Pity it seems so complex though
You already can download the code from Github. Only Android-L compatible however.
typical android; create another slightly similar, but yet different and without any real benefit thing to solve a non problem we already have several solutions for. Not that it impacts the quality of this great write up; thanks for the info.
I think Designing RecyclerView was 1 of major steps towards handling everything from system side & let user write minimum code (as compared to extending traditional BaseAdapter), I have built libarary which eases out the Multi-Row-Type support for list-view, could you look into it & provide your feedbacks that how can I take my lib towards more usefullness.
https://github.com/birajpatel/EasyListViewAdapters
Thank you for sharing this information. Very helpful!
It’s posible to compile it on api 14 or abobe.
Not at the moment, until Google reduces its minSdk on new support libraries. I can imagine you can always copy all class sources into your project, but it’s not recommended to use them on production because it may have big changes and won’t work anymore.
I compiled it to api 14
Please let us know how!
Set your compile SDK to 19
Set your minsdk to 15
Set your target SDK to 19
Add these to the dependencies
compile ‘com.android.support:cardview-v7:+’
compile ‘com.android.support:recyclerview-v7:+’
compile ‘com.android.support:palette-v7:+’
Add this line to your android manifest.xml inside the manifest tag
I’m excited to see what the grid view looks like. I hope it scrolls both horizontally and vertically!
Your comment box is stripping the tag you’re supposed to put in the manifest
uses-sdk
tools:node=”replace”
Any idea on how to use
compile ‘com.android.support:appcompat-v7:21.+’
With pre-L devices? Reason I ask is it looks like there is a copy of the Material style in it.
A dummy example. See AndroidManifest file
https://github.com/HelmComputers/HelmCarrouselDemo
i found that on a Reddit post. In AndroidManifest.xml. on manifest tag add that xmlns:tools=”http://schemas.android.com/tools”
then you can use the new feature added in the new Android studio.
By doing that you tell the manifest merger that is able to replace the minsdk
sorry it seems that posting the last comment one line has deleted.
you have to add this
uses-sdk tools:node=”replace”
Hi, glad to know someone is also trying out this new stuff so soon. Did you get your data set changes to work properly for your adapter? I have tried notifyItemInserted, notifyItemRangeInserted and notifyDataSetChanged and none of them seem to work.
I only tried notifyItemInserted and notifyItemDeleted, and both worked. But you also have to remove the items from your list. Check the example linked in this post, I’m deleting the items when clicked.
Thanks, it was actually a problem reporting back to the main thread. I have a working example here: https://github.com/wmora/openfeed
Hi, You mentioned that DefaultItemAnimator works quite well.
Can you elaborate more ? ‘Cause I tried the code on emulator and when i use notifyItemInserted(position), the list doesn’t refresh automatically. I need to scroll up & down to see the new item. When I use notifyItemInserted(position), i can see the new item automatically. But, there is no auto animation. Thanks in advance.
Check the example at Github from this article, maybe there’s something you are missing.
When I click the item quickly,app stopped
Yes, there are some known unsolved issues at that example. I accept pull requests if you find some time to find a solution.
Just add catch IndexOutOfBound… there will be not any Force Close….
Thanks for a very nice article… I am trying RecyclerView as a Section Header List or Sticky header list,Do you have any idea how can I achive this..
Not an easy way. You would need to create your own implementation of LayoutManager. I think the use of LayoutManager is too difficult right now and that we will se big changes in final release. Or, at least a few more standard layouts rather than LinearLayoutManager.
Thanks you for article
Hi your Blog was awesome! I like to have different types of views for each row in the list ( heterogeneous list), in that case how I best make use of recyclerView.. Earlier I was achieving using List view getViewTypeCount() and getItemViewType(). Can you put some some light on this ?
Great post! I forked your repo and implemented the hack found in Reddit post mentioned above (http://www.reddit.com/r/androiddev/comments/297xli/howto_use_the_v21_support_libs_on_older_versions/). It now works great on pre-L devices. You can see the fork here: https://github.com/bkurzius/RecyclerViewExtensions
ViewPager make removing view real pain , what about recycleview replace viewpager , does it got better support with dynamically add and remove views? and also visuality could recycleview replace viewpager?
OK, finally it works even on Kitkat, using the most updated SDK and support library.
I have a question though:
How should it handle filters? should it work by implementing Filterable, just as before, or does it have a new way of doing it ?
Thank u was really help full.
Hey AntonioLeivaGordillo thank you for the nice article but i have problem when deleting views quickly my app crashes and i get this error
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 0(offset:-1).state:2
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3300)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3258)
at wappi.AfricanFashion.BaseLayoutManager$RenderState.next(BaseLayoutManager.java:1330)
at wappi.AfricanFashion.GridLayoutManager.fill(GridLayoutManager.java:55)
at wappi.AfricanFashion.BaseLayoutManager.scrollBy(BaseLayoutManager.java:840)
at wappi.AfricanFashion.BaseLayoutManager.fixLayoutEndGap(BaseLayoutManager.java:616)
at wappi.AfricanFashion.BaseLayoutManager.onLayoutChildren(BaseLayoutManager.java:544).
But it doesn’t happen when i delete items slowly any ideas .
Yeah, that was a bug in my code but I can’t remember why. Don’t use those layouts anyway, there is a GridLayoutManager in final SDK. The code on that repository is only thought as a didactic example, not prepared for production code at all.
Okay thank you for the info.
Hey, you said there’s a GridLayoutMangere in the final SDK? What do you mean? I’m targeting SDK 21, and using the recyclerview support library v21, but Android Studio still won’t resolve GridLayoutManager. What am I doing wrong?
https://developer.android.com/reference/android/support/v7/widget/GridLayoutManager.html
I am using recyclerview in my app but it is not appearing in all versions except in lollipop (nexus 5 with 5.0.1). How can I solve this? I have tried in jellybeans and kitkat… in sdk manager all is updated.
I Found a little BUG, When the Items size/length is even (20,18,16)….. if i click last 4 item it will error. and give indexOutOfBound the REST is FIne…. Something error in BaseLayoutManager… 🙁
Experiment with RecyclerView
https://github.com/rahulrj/Swipe_RecyclerView
Very nice! Thanks.
how can we call onitemclick listeners on recycler view from activity ?
How would you implement RecyclerView with CursorAdapter and CursorLoader? I am getting my data from DB, and wish to present it in the RecyclerView.
How to implement search widget with a recycler view?
Does it work on android 5.0
This article was based on the preview SDK, so it may not work perfect. I´d suggest to take a look to my latest article, where you can find an example with RecyclerView, among others: http://antonioleiva.com/materialize-app/
endless RecyclerView with progress bar at bottom while loading more data from service ?
On filter of recyclerview using same adapter how to set on item click listener to that item get appropriate information
do you have any news about sections or sticky headers to RecyclerView?
Not yet, sorry.
hi.
I am new in android programming and in wanna use a edittext to search in recycleview. i mean write a filter but i don’t now how?
can we perform delete item also. i read that recuclerview doesn’t allow deleting. is it true.
Yeah, you can use notifyItemRemoved method in RecyclerView.
Thank you so much
hello where is ur drawable folder with image?
Hello Sir,
Sorry for my bad English. I wanna ask about recyclerview.
I have 10 items in my recyclerview, then I wanna remove item 0,1,2
like this example :
for(Integer i = 0; i<3; i++){
list.remove(i);
adapter.notifyItemRemoved(i);
adapter.notifyItemRangeChanged(i, list.size());
}
then the result I have :
1,3,5,6,7,8,9,10
item 1 not deleted, but my item 4 been deleted.
Can you help me Sir…
Best Regards,
Zigic