How to understand RecyclerView properly - android

I have watched a lot of videos on RecyclerView but I am very confused on whether the ViewHolder is an adapter that changes the view or does it really just represent each item that is displayed on the screen.
How can I understand the concept more?

Let's see if this helps.
The general job of any list-style view would be to display a long chain of views, each representing a piece of data, most likely from a list.
Now imagine we consider the simplest implementation, where it draws all those views when it is created and allows you to scroll through them. This is obviously very inefficient for performance as a long list would require a lot of processing all at once.
RecyclerView aims to solve this and only creates enough views to fit on the screen and when scrolling, changes the content of those views seamlessly to reflect more data.
Now these views are created initially as empty blueprints and the RecyclerView wraps them inside something called a ViewHolder, which can not only hold the view but also pointers to different parts of the view, which saves doing even more work every time new data is displayed. Then initially and when scrolling, the RecyclerView 'binds' the relevant data to view holders.
The job of the adapter is to tie this process together and has three methods that require you to provide a concrete implementation:
getItemCount - expected to return how many items there are in the full dataset
onCreateViewHolder - create a view holder representing a generic row
onBindViewHolder - bind data to a view holder, therefore updating the rows content when given the view holder and the position in the dataset that should be bound

Related

Why recyclerview is faster than listview [duplicate]

This question already has answers here:
Android Recyclerview vs ListView with Viewholder
(7 answers)
Closed 3 years ago.
I was reading about the difference b/w recyclerview and listview and found out that recyclerview is faster than listview.
I tried to search online but not found any satisfactory answer I know it is used ViewHolder pattern and Notifying adapter but what does it does intearlly so it is faster?
Recycler View you could say is an efficient way to create list of views.
If you have 1000 items like ur contact list , and If ur visible screen can show only 10 items at once, it will Create only 10+1 (or +2) Views and as u scroll , items/views that left will be reused (not create) to show new data.
Recycler View by default does this, where as List View by default doesn't do.
There are some differences between these two views.
ListView is a bit heavy and it has a lot of responsibilities. Whenever we have to handle the list, such as to configure it in some way, the only way to do this is through the ListView object or inside the adapter.
A lot of bad things in the ListView were fixed or changed in the RecyclerView. It’s more efficient by default, the layout is separated and we have more possibilities over the data set inside the adapter.
These are some crucial differences between ListView and RecyclerView:
1 ViewHolder
The ViewHolder pattern allows us to make our list scrolling act smoothly. It stores list row views references and, thanks to this, calling the findViewById() method only occurs a couple of times, rather than for the entire dataset and on each bind view.
The RecyclerView’s adapter forces us to use the ViewHolder pattern. The creating part (inflating the layout and finding views) and updating the views is split into two methods — onCreateViewHolder() and onBindViewHolder().
The ListView, on the other hand, doesn’t give us that kind of protection by default, so without implementing the ViewHolder pattern inside the getView() method, we’ll end with inefficient scrolling in our list.
2 LayoutManager
The LayoutManager takes responsibility for layouting row views. Thanks to this, RecyclerView doesn’t have to think about how to position the row view. This class gives us the opportunity to choose the way that we want to show the row views and how to scroll the list. For example, if we want to scroll our list vertically or horizontally, we can choose LinearLayoutManager. For grids, it is more suitable to choose the GridLayoutManager.
Previously, with the use of the ListView, we were only able to create a vertical-scrolling list, so it wasn’t that flexible. If we wanted grids on our list, we had to choose the other widget for that — GridView.
3 ItemDecoration
A duty of the ItemDecoration is simple in theory – add some decorations for the list row views – but in practice, it’s that simple to implement if we want to create a custom one. In this case, we should extend the ItemDecoration class and implement our solution. For example, the RecyclerView list has no dividers between rows by default and it’s consistent with the Material Design guidelines. However, if we want to add a divider for some reason, we can use DividerItemDecoration and add it to the RecyclerView. In case we use the ListView, we have to figure out rows decorations by ourselves. There is no helper class like ItemDecoration for this widget.
4 ItemAnimator
The last but not least component of RecyclerView that I want to mention is ItemAnimator. As we can expect, it’s handling row views animations like list appearance and disappearance, adding or removing particular views and so on. By default, RecyclerView’s list animations are nice and smooth. Of course, we can change that by creating our own ItemAnimator, which is also not that easy. To make it easier, we should extend the SimpleItemAnimator class and implement the methods that we need (just add animations to a ViewHolder’s views). To be honest, implementing animations on the ListView was a pain. Again, we had to figure out how we want to handle them.
5 Notifying adapter
We have a couple of cool notifiers on the RecyclerView’s adapter. We are still able to use notifyDataSetChanged() but there are also ones for particular list elements, like notifyItemInserted(), notifyItemRemoved() or even notifyItemChanged() and more. We should use the most appropriate ones for what is actually happening, so the proper animations will fire correctly.
Using ListView, we were able to use just notifyDataSetChanged() on the adapter and then had to handle the rest ourselves, again.
Because of ViewHolder Pattern.
Thats was the simplest answer. Now for some details.
What recycler view does is what it's name indicates "Recycle", yes it recycles items, and it does it with the help of ViewHolder Pattern.
By Using ViewHolder we do-not need to call findViewByID() every time we go through getView()method. The reference for all rows are stored in-memory. This increases the performance significantly, as findViewByID()is a heavy process.
Hope this clears your confusion.

Can data be cached in Android RecyclerView Adapter?

We cache the views in ViewHolder so that too many findViewById() calls could be avoided. In the same way, whether data can be cached in RecyclerView Adapter?
I heard that views are cached in ViewHolder but I am not sure whether data is cached when we use Adapter? If data caching is not provided by RecyclerView Adapter, application can still be crashed if too many calls to data sources occurs?
What exactly you mean my by cache if you meant in the Sense of Image you can Use library like Picasso and perform like this and cache Images. and if you Mean cache in the sense of data your List or Array is already Working as cache.Only visible Views in ListView have Data Rest is Imaginary only data reside within the List or array!
No You can't
In Android RecyclerView, only the number of views which will be visible are created. It is handled by the onCreateViewHolder() method.
And when the user scrolls the list, the views which go out of the visible area are reused by populating it with new data. This operation is carried out in the onBindViewHolder(ViewHolder viewholder, int position) method.
As views are recycled for new data, there is no point of caching the data in viewholders.
By the way if you look at onCreateViewHolder(ViewGroup parent, int viewType), you will notice that there is no position parameter. which means you will not even be able to link your list item data, because the ViewHolder is going to be used for multiple positions in the list.

What are the responsibilities of, and differences between, a RecyclerView Adapter and RecyclerView LayoutManager?

I am trying to understand the RecyclerView but I can't understand the difference between the Adapter and LayoutManager.
Can anyone explain it to me?
The adapter is used to create (and bind data to) views that correspond to each item in your dataset.
The layout manager is responsible for the layout of these views.
The adapter doesn't know how the views will be positioned and sized. This means you can swap the layout manager without having to change your adapter code e.g. switching from a LinearLayoutManager to GridLayoutManager.
Check out this answer for a deeper (though still high-level) explanation (scroll past the initial code block to the section about RecyclerView philosophy):
ListView to RecyclerView Migration for CustomView
So in Recycler View you need an Adapter to manage the data which will contain the Recycler view. Adapter will take the data it can come from internet or from internal database, than adapter fetches the dat when it gets the data without an error it comes back to adapter(e.g.adapter grabs data from dataset) then it shows the data in the View Holder in your card like a one cell in the Recycler View, View Holder is a class that manages the view and than that view appears in the Recycler View. The above image which i tried to draw shows that process for Horizontal Recycler
In my case i found these benifits when i working on them
Basically an Adapter is used to gather all corresponding data what you provided
to all views defined by you
after gathering all data it wants a layout to display thease views for this layoutmanager gives a flatform to show them .

why does the ViewHolder pattern work?

I learned Android's ArrayAdapter today, and find there is a commom pattern which uses a ViewHolder to hold Views' reference instead of calling findViewById everytime.
But how does it work? Adapter is usually used to display a list of View(Group)s, If I cache the View, why don't they all reference to the oldest one?
If you want the best explanation on how the ViewHolder works, check out Romain Guy's Google I/O 2009 talk in youtube , specially the first 15 minutes.
In short, the Adapter functions as a link between the underlying data and the ViewGroup. It will render as many Views as required to fill the screen. Upon scrolling or any other event that pushes a View is out of the screen, the Adapter will reuse that View, filled with the correct data, to be rendered at the screen.
The getView(int pos, View view, ViewGroup parent) method will use the right View at any time, regardless of your layout. I do not know the internals of this, but I'm sure you can browse the source code for any adapter (such as ArrayAdapter.java) if you're interested.
The ViewHolder just keeps a pointer to the Views as obtained by view.findViewById(int id). It is the Adapter responsibility to return the right data corresponding to any position.
Slides 11 to 13 of Romain's presentation will make it a lot more clear than anything I can write.
Sorry but denis' answer may be wrong.
In fact, the view instances(and ViewHolders) are as many as your screen can display.
If your screen looks like:
[list view]
the first item
the second item
the third item
the fourth item
You will have 4 instances of views. If you scroll screen, the first will disappear but be pass to getItem() as convertView for you to create the fifth item.
So you can use the references in first ViewHolder.
I believe the work beneath the list view is something like this (considering we have only one item view type):
do once:
inflate item view from layout, cache it
repeat for every item:
ask adapter to fill the data into the view
draw the view on the screen
move to next item
so you have the view which is inflated from xml layout and can be reused for drawing multiple list items. ViewHolder speeds it up a bit more by saving getViewById lookups.

Scrolling large lists of Cursor-based adapters is faster than much smaller lists of in-memory adapters

I have an Android app that has both CursorAdapter based ListViews (backed by sqlite) as well as custom BaseAdapter based ListViews which are built on the fly from JSON pulled down from a server.
The data displayed in both is identical - an image and a couple of TextViews. My Cursor-based ListView has 3000 rows, the JSON-based ListView has about 30. However, scrolling down the list is significantly faster for the Cursor-based adapter. For the JSON-based lists, the data is all fetched before the rows are made visible. Images for both types of lists are downloaded on-demand.
I have both ListViews configured identically - both with fastScrollEnabled, scrollingCache and smoothScrollbar set to true.
I'm looking for leads on how to go about trying to figure out what's going on here and to potentially fix it so that the JSON-based ListViews as as fast as the Cursor-based ones.
I have a similar thing in my application, except I only have json backed ListView and I also have about 30 items in it (with data constantly changing and animation playing to reflect changes).
It would be much more easier to detect a problem with some provided code from your side, but here are couple of tricks you can sue for optimization.
Reuse convertView that is passed to you as one of the parameters in getView method, it really speeds up the scrolling.
Either create your own row view (by extending some layout, or ViewGroup), or use setTag on a row you return form your getView method. In this tag, you should keep an object that contains references to views in that row, so you wont be searching for them with findViewById everytime a row is requested.
Object can be a simple static class like
private static class ViewHolder {
ImageView image;
TextView text;
}
On the first time (when the convertView is null and you need to create a fresh row) you just create instance of your ViewHolder and set those parameters to refer to parameters from your newly created row (by calling findViewById), and put this instance in row's setTag method.
Next time, when you reuse convertView, just call getTag and in the tag you recieved you'll get references to views in that row, so you won't be needing to call findViewById anymore.
Of course, you might already done all those things.
P.S. I advice you (if you haven't already) to watch Google I/O presentation about ListView's. A lot of useful information there: http://www.youtube.com/watch?v=wDBM6wVEO70

Categories

Resources