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.
Related
I'm trying to create a way to search inside a RecyclerView with animating the items that have been searched (hide the ones that don't meet the condition, and add the ones that do, if they're not already in).
Of course, the simplest way to search a RecyclerView is just filter the list and notifyDataSetChanged(). But most developers know that this call recreates the adapter from scratch, almost like it was just assigned. Also, this call doesn't give any feeling of the items being searched, as all the items appear at once.
I've tried creating some way where the items get added or removed to the list as they meet/not meet the condition, but this loses the order of the items. Unless of course you search where the item is in the main list, and put it where it belongs. Which makes the searching longer since you're searching again every insert.
I looked into using a TreeMap, but trees can't be accessed by index, only by key.
I've also used SparseArray, the only problem was the SparseArray doesn't tell you in what index was the item inserted, you'll have to search for the item again (in order to notify the adapter).
Is there a recommended way of doing it? Some tutorial I have missed? Searching around I could only find the notifyDatasetChanged() solution.
I believe what you're searching for is DiffUtil.
Here's a well explained Medium article explaining it's usage.
Another interesting answer I've come across when looking into this is the SO Answer provided by Xaver Kapeller (Just search for SortedListAdapter in the page, although his answer is a very nice read imo). His SortedListAdapter library makes the code much more simpler and cleaner.
I'm using recycler view with grid view (every item contains a grid) with thumbnail images after adding images in view it start uploading, and i need to change some values (status) in model at the time of start and finish upload.
What I'm currently doing is change values in model and call notifyDataSetChanged, but it causes to slow down application (hang some times) because it updating every child of list :(
Can any one help me with this?
Call notifydatasetchanged() for particular Gridview adapter only. Don't call notifydatasetchanged() for complete recyclerview adapter.
Try setting it again to the adapter.
gridview.setAdapter(your adapter)
-passing your new list to your adapter.
I believe notifyDataSetChanged updates all of your values regardless if they have a change or not that is why it is slow. I suggest you try using notifyItemChanged(int position) instead.
According to recyclerview docs this is what notifyDataSetChanged does:
This event does not specify what about the data set has changed, forcing any observers to assume that all existing items and structure may no longer be valid. LayoutManagers will be forced to fully rebind and relayout all visible views.
Old question but similar to what I'm experiencing.
RecyclerView is usually incredibly fast when changing list details. But manipulating a lot of images can really slow it down if you're not careul.
I'd recommend you try removing the images and repeat it so you can see if that is just as slow. I suspect this will be a lot faster.
If so, make sure you're handling the images off the UI thread. The Android docs recommend you use a library such as Glide which also handles sub-sampling the image to make sure it's the right size.
Hope that helps!
I have a RecyclerView with setStackFromEnd(true) representing a chat list. And I want to load older messages when the list is scrolled to the top. I managed to do this using onScrollListener.
But when I add items to the adapter with messages.addAll(0, aListWithNewMessages) (messages is data set for adapter) and call notifyDataSetChanged(), new list items (as expected) appear before the existing ones and shift them down (not the experience a user wants), and I want to add them silently so a user shouldn't see it.
So my guess for how to tackle this issue is to scroll list to somehow previously saved position.
I understand that this is not a bug or an unexpected behavior, so please help to sort it out.
Thanks
Try being more specific. Instead of calling notifyDataSetChanged() use notifyItemRangeInserted or similar RecyclerView methods. That will allow RecyclerView to know what to do and will provide much better UX.
I have a regular Gallery widget. For some reason, the getView method in my adapter is getting called once for every single element in my list of items. Effectively creating all the layout elements many more times than necessary and leading to slower loading times as well as outofmemory exceptions.
Reading through several posts I understand that Gallery does not recycle, but I don't think that it should be creating every single item from the get go. Would appreciate any suggestions on how I can prevent all images from being loaded on load.
I had the same issue but they way I solved it was related to the component that I use for loading images. Anyway I think this post can be useful for finding a solution
So I actually ended up sort of solving this. Using the answer from this question the problem disappeared and the Gallery no longer pre-loads all of the pictures.
I still don't know the cause of the original problem, or the way to solve it there. But this works for me.
I have a ListView with custom rows. When any of these rows is
clicked, the ListView's data is regenerated. I'd like the list to
scroll back to the top when this happens.
I initially tried using setSelection(0) in each row's OnClickListener
to achieve this but was unsuccessful (I believe because the ListView
loses its scroll position when its data is invalidated - so my call to
setSelection is undone. I still don't understand how the ListView
decides where to scroll to after invalidation, though).
The only working solution I know of was given by Romain Guy here:
http://groups.google.com/group/android-developers/browse_thread/thread/127ca57414035301
It involves (View.post)ing the call to _listView.setSelection(0). I
found this to perform quite poorly.
The newly generated list shows up with its scroll location unchanged
and there is a considerable delay before it scrolls back to the top.
Is there any better way to achieve this functionality?
Any help would be much appreciated.
Thanks!
call listView.setSelectionAfterHeaderView(); to scroll to top
I have tried lot but this one worked for me
list.smoothScrollToPosition(0);
I simply use listview.setSelection(0);
Works fine for me.
If you need instant scroll just after ListView adapter's data was changed, pay attention that it might not be yet populated. In this case you should post() your setSelection() or setSelectionAfterHeaderView() via Handler so it will be called later in the queue.
listView.Handler.post(new Runnable() {
#Override
public void run() {
listView.setSelectionAfterHeaderView();
}
});
This worked for me.
Personally, I recommend you find a different UI pattern. It is possible that users will find your current "click, and the list changes in situ" approach intuitive, but I am skeptical.
You could try subclassing ListView and overriding layoutChildren() to chain to the superclass, then call setSelection(0) in the case where that is needed. If the "considerable delay" is due to just the post() call, this should clear it up.
as a workaround, you can create a new adapter containing the new regenerated data, then call ListView.setAdapter. after that call ListView.setSelection(n).
btw, the solution provided by commonsware is worked.
On some different requirement.
If you want to scroll up just like while chatting.
mListView.smoothScrollToPosition(mAdapter.getCount());
This one worked fine when you want to focus the edittext from listview header
listview.setSelectionFromTop(0,0);
If you want to select the particular index view from listview then
listview.setSelection(index); // o for top