Can RecyclerView preload the first n item on the list? - android

I have a listing of some item and I am using Glide to load an image onto an ImageView. The problem is, if a particular item, scroll-enter the screen, that is the only time I saw image is being drawn using Glide. This is noticeable when I put crossfade when the image has finished loading.
I know from the start the number of items needed and couple of other items like header and footer. I am thinking of just making a very long view to handle everything and dynamically add those known items at onCreate and just use ScrollView which I have done. I currently implemented a simpler way using a RecyclerView but I having trouble regarding the timing of onBindView call.
What I want is to load first 5 items before they become visible into the screen. This I hope will trigger the method where I bind the image onto the ImageView with Glide before it is fully visible into the screen.
I followed this tutorial and its not working for me. Here is my current setup:
mComicListingAdapter = new ComicListingsAdapter(getContext(), Constants.CHAPTERS, (ComicListingsAdapter.Callback) getActivity());
mRecycleViewHomeScreen.setAdapter(mComicListingAdapter);
mRecycleViewHomeScreen.setHasFixedSize(true);
mRecycleViewHomeScreen.setItemViewCacheSize(42);
mRecycleViewHomeScreen.setLayoutManager(pcll);
Is this possible in RecyclerView? Or maybe I should try dynamically creating ImageView and appending them to a parent View as I have done so. It looks great but there is a lot of things to do in my case using this method. I am just curious if I can direct RecyclerView to load n-amount of items in advance.
Thanks!

I've found a blog post where author suggest to extend LinearLayoutManager and override getExtraLayoutSpace().
And it worked. More items were preloaded depending on the number of pixels returned in getExtraLayoutSpace().
P.S. I've not checked yet how that affects performance, especially on pre-lollipop devices.
Sample:
val customLayoutManager = CustomLayoutManager(this)
recyclerView = findViewById<RecyclerView>(R.id.recyclerView).apply {
layoutManager = customLayoutManager
... //
}
class CustomLayoutManager(context: Context?) : LinearLayoutManager(context) {
override fun getExtraLayoutSpace(state: RecyclerView.State?) = 2000
}

Views are created dynamically at runtime and you can only access view items at onBindViewHolder method of adapter. You want to load images before setting adapter to recycler view. Firstly the getItemCount method is being called which will look for number of items and then onCreateViewHolder method is called to draw a row into your RecyclerView.
So this is not possible in RecyclerView to access items before setting any Adapter. You need to achieve this in some other way by dynamically creating an ImageView, for example.

Related

Know whether a view is completely visible in a recycler view from its adapter

I saw a lot of posts that show the currently entirely visible item in the recycler view but, from the activity. But, I want to know about that from the adapter. If the view is completely visible, I want to start playing a video and when it is hidden, I want to stop it.
you have to set LayoutManager for RecyclerView. if you are using most common LinearLayoutManager, then it's have some methods for your purpose:
findFirstCompletelyVisibleItemPosition()
findFirstVisibleItemPosition()
findLastCompletelyVisibleItemPosition()
findLastVisibleItemPosition()
There are also similar methods in StaggeredGridLayoutManager, e.g. findFirstVisibleItemPositions
And general way would be to use bare LayoutManager and its isViewPartiallyVisible method, but this probably needs more your code for particular use case

RecyclerView inside RecyclerView, app crashing due to high memory consumption

I wanted to create a recycler view of photo albums and when the user taps on an album, it expands to grid layout showing images in that album.
For example, non-expanded:
and expanded:
The layout of outer recyclerView item only contains a textView, checkbox, and an invisible recyclerview that becomes visible on click of the item.
I declared the outerAdapter like this:
photosVideosAdapter = new PhotosVideosAdapter(getContext(),new ArrayList<PhoneAlbum>());
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setAdapter(photosVideosAdapter);
Here is the onBindViewHolder of outer adapter:
holder.tvFolder.setText(phoneAlbums.get(position).getName());
ArrayList<PhonePhoto> phonePhotos = phoneAlbums.get(position).getAlbumPhotos();
InnerAdapter innerAdapter = new InnerAdapter(context, phonePhotos);
holder.innerRecyclerView.setHasFixedSize(true);
holder.innerRecyclerView.setLayoutManager(new GridLayoutManager(context,3));
holder.innerRecyclerView.setAdapter(innerAdapter);
.... OnClickMethod to toggle visibility of innerRecyclerView
And onBindViewHolder for inner adapter:
Glide.with(context)
.load(phonePhotos.get(position).getPhotoUri())
.override(200,200)
.into(holder.imgThumbnail);
The problem is that if inner recyclerView contains more than 200 items, the app crashes due to high memory usage. But as you can see, I'm using glide to load images and also RecyclerView shouldn't create all the views at once. But, what I can see is that the inner RecyclerView is creating all the item views at once which is causing the app to crash.
How can I fix this problem? Any help will be appreciated.
Trust me, dont go with recyclerview inside recyclerview.
I had the similar situation in my current app where my colleague built solution by using nested recyclerview.
I rewrote the entire logic using insert and delete with animation and multiple view type.
It will involve some extra code to manage it. But the result would be quite satisfying.
In fact, I used same logic in iOS collectionview as well. App on both platform is live.
Try add this to your manifest.xml
android:largeHeap="true"
Your memory consumption is likely to high because you retrieved all the photos from the album at once with the line:
ArrayList<PhonePhoto> phonePhotos = phoneAlbums.get(position).getAlbumPhotos();
I assume you are also pulling all the photos at their original quality, so having 200+ full size photos on phone's RAM all at once could be the cause of the crash.
One way you could fix this would be to load in lower resolution previews of the photos into RAM, and once a photo is actually being displayed in the RecyclerView you could load a full resolution photo.

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.

RecyclerView onBindViewHolder called multiple times for one item

I have used the RececlerView with the ViewHolder pattern for a while now.
Im am implementing a custom Adapter.
Im am not searching for a specific bug help in my code.
I was just wondering, if it's normal, that the onBindViewHolder method is called multiple times (for the same item) while scrolling to the end of the list and scrolling back up. In this case onBindViewHolder is called again for item 0 and 1 (the list contains 7 items in total)
Is there any possibility for this method to get called AGAIN without notifying that the datasat has changed?
Im a bit confused.
Kind Regards,
Palm
Yes it is perfectly normal for a RecyclerView to call onBindViewHolder() multiple times.
A RecyclerView only creates minimum number of Views needed to fill the screen. And it works by reusing the old/created Views. So that when you are scrolling down the View that hid during the scrolling to the top is removed and brought next to the last visible View and added there. But since the View is currently bound with old data onBindViewHolder() is called again to ensure that the View is bound with only the correct data before it is rendered.
Similarly you'll notice that onCreateViewHolder() is only called the exact minimum number of Views it needs.
For a better understanding of how the RecyclerView works I suggest you read up on Recycler, LayoutManager and Recycler.Adapter the three core parts of a RecyclerView.

Improve android listview performance for refreshing and scrolling

I have a ListView which onItemClick selected item changes its layout, pops different buttons. If any other item is selected, the previous selected one returns to normal. My ListView adapter works fine but refreshing the whole list with notifyDataSetChanged() in my adapter takes too much time.
My problem is to refresh only the changed items in the ListView.
And also I would like to have suggestions for better scrolling performance.
try to implement View Holder Pattern it increases the performance of loading and scrolling of ListViews
Making ListView Scrolling Smooth | Android Developers
Using lists in Android (ListView) - Tutorial - Vogella
from the docs:
Your code might call findViewById() frequently during the scrolling of ListView, which can slow down performance. Even when the Adapter returns an inflated view for recycling, you still need to look up the elements and update them. A way around repeated use of findViewById() is to use the "view holder" design pattern.
you can define one method in adapter class which will return current item view. in onitemclick use this method to make changes in clicked item. You can define class view type class variable in activity and store previous view there...
ListView scrolling performance slows down when widgests like textviews, images are at the bottom of the layout hierarchy.
So for improving list performance one should design item xmls with minimum layout tree levels.

Categories

Resources