I have seen this question asked by "vbjain", but answer that are given are not satisfactory for me.
I am also facing same problem, I have a huge list where i need to do extensive calculation in getView() which are unavoidable, my list contains live data which gets generated at the time of displaying list, so i can't avoid these calculation other than doing them in getView function.
I don't know why getView method is getting called when i am switching focus from/to list view, cause of getView is getting called at the time of changing the focus and i am doing calculations in getView my application gets stuck for 2-3 seconds and then it switches focus from/to list view.
Is there any way by which we can avoid this behavior of list view.
Thanks.
The list view behaves the way it does largely for performance reasons, I can't recommend this video enough for people working with list views, Romain Guy explains everything clearly and concisely. If you want your list view to perform, follow his advice.
Related
I think I've read all the answers to all of the similar questions, and none of them seem to be fixing my problem,they're only workaround. I have recycler view with pictures taken by camera and they only update on scroll.
Using a smoothScrollToPosition() is workaround and I want to know the cause of this issue and fix it.
It's really weird because when a open my fragment and have a couple of images in the recycler view which I added earlier, deleting elements works perfect, but when I add new image from camera intent even the notification for deleting stops working, I have to do a scroll to refresh items in the adapter.
This is the part where I set the data:
viewModel.photos.observe(viewLifecycleOwner, Observer {
list->adapter.data = list
}).
Of course data is set in OnUiThread :
I checked with the debugger-- elements in list are updated.
Does anyone know the cause of this issue?
You have to tell recyclerView.adapter what exactly changed by calling notifyItemChanged. There are also other methods for inserted items, moved items, deleted items, etc. You can look at the full documentation here:
There is also another way by implementing a DiffUtil. You can research about it more. But the difference is that by using DiffUtil, you won't have to manually call those notify methods yourself.
Also, the old/unoptimized/unrecomenended way to do this is to simply call notifyDataSetChanged().
P.S. I highly think you found the somewhat the same answer while searching online and might have thought it as simply "a work around". I'm here to tell you that this is how its supposed to be handled.
I need to implement the next logic in Android:
We have RecyclerView with hours of days (8.00-17.00, after 17.00 we see 8.00 of the next day, so the list is infinite) and should add events according to their time. I implemented it using LinearLayoutManager and view holder is a day where I add events to absolute position of view). But I don't like this way, because every item view is a bit havy and list doesn't scroll smoothly when draws new item. Please help me find correct way to implement it.
If the scrolling is not smooth then probably your onBindViewHolder is too heavy. There is no generic advice in this situation. You need to run Android Studio->Android Monitor->CPU->Start Method Tracing and analyse what actually slows down creating day view. Then optimise that part.
Also carefully check if you are not running any disk or database access code in UI thread. Move it to a separate thread.
I searched for hours but didn't find a suitable solution for me.
What I want to do: in my ListFragment I use the onListItemClick(...) method to handle the click events. Here, I change the background of the row item. But unfortunately every time the onListItemClick(...) is called, also the getView() from the adapter is called and updates all 8 visible row items. That takes to much time: 0.5 seconds. Because the row layout is pretty complex (2 Images, 8 TextViews).
So I want to update only the row which is clicked. I want to use this solution but that has no effect, when the other 7 row items are updated anyways.
I already followed these advices to speed the list up, but it's still to slow.
Any help, ideas and thoughts are appreciated. :)
Thank you!
[EDIT]
Thanks to CommensWare for giving me some new ideas. What I did now was to check what traceview says. And the result is, that the delay is devided in two parts. The first 300ms of the delay takes the "FastXMLSerialzier.escapeAndAppendString()" with over 22.000 calls. That seems a lot! In the second half, many, maybe all, onMeasure()-methods of the views and layouts are called.
What I tried:
I filled every textview with static dummy values in the adapter and excluded the part with loading the images. It changes nothing, traceview shows the same picture.
In the second try, I looked at the LinearLayout of my list item and replaced every "wrap_content" I found with "match_parent" - nothing. Still the same.
I am still open for your thoughts and hints. :)
You have no control over when and how frequently getView() is called.
If it really takes 500ms for you to generate 8 row Views, then there is something wrong with your code. You can use Traceview to determine specifically where you are taking the time, so you can attempt to do something to improve performance (e.g., caching).
I have a Gallery, which has an adapter connects to it. In the getView method, i have a custom layout, so that I can i have image and caption displayed together
The image is downloaded from an URL, which is done asynchously, and working as expected.
Currently i make each item to fill the screen, so i only have one item display at a time, basically i want to make it like a slide show.
let me be clear, currently i have an activity, and it only has one View, which is a Gallery.
problem occurs when I am swiping, the image bounces and stays at the same image. i need to swipe many times, hard, and long swipe, then i can get to next image.
i put a debug message in my custom adapter in the getView(), it seems getView is getting called many times (4 times), and position being passed is either the current position or the previous one, which explains why i am stuck at the same screen.
if i remove the remote downloading image part, or just use a static image form the phone, i don't have any more issues, in fact, the getView only gets called once, with correct position.
i am very frustrated, not sure what the problem is, could it be because i am downloading image asynchously, which will cause the image to update which causes getView to get called again to redraw itself?
i am not sure..
please help
Unfortunately this is a bug with gallery. Listviews will scroll nicely regardless of data being updated asynchronously. However, the gallery is just not coded up to par with the listview
When the gallery tries to update a visible view (due to your image loading callback) this view will "snap" back to the focused position. If you are changing the view in any way when it is scrolling it will snap. This is likely why you have to scroll hard to get away from the current view. It is trying to perform a callback on your view and only scrolling fast will prevent the callback from occurring before you move away from that view.
I've reported this bug a while ago here:
Android Issues
There are a few workarounds posted in there you can try if you are set on using a Gallery.
Unfortunately it hasn't gained attention from the Android developers.
It seems the issue is caused with views being set to "wrap_content" and the gallery having to remeasure/redraw its views
I have since migrated away from using the gallery and instead use a ViewPager. It is much easier to manage and you don't have to worry about this problem. This has been a known problem with the Gallery since the gallery was first introduced. I have no idea if this was fixed in any of the newer Android versions (3.x/4.x). As of 2.3.7 it is not fixed.
At first you should note: Any AdapterView (Gallery, ListView etc) doesn't guarantee that each time getView() method is called it will pass the same View instance parameter. It only guarantees that each view will have the same type (see Adapter.getIntemViewType() method docs)
So, when you start image downloading you should only specify position of the element. Then after the image has been downloaded you should bind specified ImageView with downloaded image in Adapter.getView() method call.
Take a look to the ImageDownloader from the Android samples here
The other approach is to use WeakHashMap in order to contain map of adapter views to its positions. I can provide you with code samples if you need.
Is there a way to call BaseAdapter.notifyDataSetChanged() on a single element in the adapter.
What I am trying to do is update the data and reflect those changes in the containing ListView. The problem is that sometimes the change is so small that it seems ridiculous that I have to refresh the whole view rather than the single item in the view that has been updated.
I am not aware of such method. If it's really important, you can always find individual item view to update. But I don't think that it worth it as Android is pretty efficient in updating list views. So it will not do much extra work (definitelly not going beyond items currently visible on the screen).