my viewpager currently only re-renders views that are two views away from what is visually seen.
example (shown respectively)
ViewA, ViewB, CurrentView, ViewD, ViewE
not rendered, rendered, rendered, rendered, not rendered`
how would I force it to reload a particular view X many views away from the currentView, there are some use case scenarios where I want it to, and other cases when I dont want it to. But currently I only know how to reload the entire adapter - where it perhaps pulls from an arraylist
I'm really not sure how to control the Viewpager - very few examples out there. All I know how to do is reset the entire list on "notifyDataSetChanged"
insight appreciated
use this method mViewPager.setOffscreenPageLimit(2) and you can set the limit of offscreen pages
I think your going too need to decouple your view and data logic (array list in this case?). If you don't want the view to change, don't change the data layer. When you call notifyDataSetChanged everything will mimic your data layer. If you want a view to change, change the data layer and call notifyDataSetChanged.
To put it simpler, the view just draws what the data tells it to, and expect that the view could update at any time. It is very similar to how listview works.
Related
Suppose I have RecyclerView with hundreds of items. There are a few different view types. When I click on an item it has to change its UI. As I see it there are two options:
change the item to a different view type and notify the adapter that it changed so that it can inflate a new view to display the new state.
have both views in a single xml file. only one is visible at any time. Toggle between them using the setVisibility function when the state changes.
there are a lot of articles online about heterogeneous RecyclerViews using lots of view types, but i have yet seen one about the best practices when item views dynamically change and the RecyclerView becomes more heterogeneous over time.
which method is best to change an existing view in a recycler view? what are the tradeoffs?
The tradeoffs are pretty obvious.
Both UIs in a single View: depending on your views, this might:
Make the Views heavy to inflate and layout
Slow down the binding process, since you have to bind both UIs
Eventually, lag down the scrolling process.
On the other hand, you have a fast, precise control over what Views should change appearance at a certain time. Having both UIs in the same place allows for finer animations and transitions between one state and another.
Different View types: I think your case is not why view types were created in the first place - they are meant for having different childs at the same time, in different positions of the list. This:
Might slow down the transition. You have to be extremely careful on how you tell the adapter to reload the objects. As you can read anywhere, you might want to avoid notifyDataSetChanged(), which reloads any object, and rather use notifyItemChanged() or such. This requires some work and attention.
Does not allow (not easily, at least) for visual transition between one state and another.
The answer is that, IMO, only you can know. You should ask yourself:
Are these Views complex? Do they have a deep hierarchy? Would having both of them reduce performance (e.g. in the binding part)?
Would it be easy to understand which views are changed, and call notifyItemChanged(int position) in the second case? Reloading the whole dataset has a huge impact on performance, if you have lots of items.
Do you need some visual transition between one state and another? Maybe you want both UIs to fit into a single container (like different informations in a CardView)? If this is mandatory, then option 1 is better.
Do you have more than 2 UIs? If so, I would go with view types, so as not to host too many views in a single child layout.
and similar questions.
I'm trying to show an animation with all Views that I've created from an adapter. When I scroll down, it shows the animation correctly, but when I scroll up, I see these Views recreate themselves and show the animation again. Then, when I scroll down, it happens again.
My assumption is that the mechanism of creating a View from an adapter is to load the View into memory; just the group of Views which are on screen right now (but above and below views are not loaded into memory). These will be loaded again when I scroll to these views, right?
Is there any way to fix this problem?
PS: Sorry for my English, I hope you understand my problem.
My assumption is that the mechanism of creating a View from an adapter
is to load the View into memory; just the group of Views which are on
screen right now (but above and below views are not loaded into
memory)
That's somewhat correct: a ListView will not try to visualize any data that isn't (at least partially) visible. It also 'recycles' views, meaning that any view that isn't currently used to present data to the user and is of the same 'type' as the next data item, may get reused.
Hence you shouldn't rely on persisting data with or make any assumptions about the existence of particular views. In stead, use something that's separate from the views; e.g. the dataset you're visualizing.
Quite often, you'll supply a list of POJOs to a BaseAdapter or ArrayAdapter. You could simply add a boolean to the POJO indicating whether it should animate or not, and change that whenever the animation for that particular item finishes. Alternatively, you could keep track of these values in a separate collection (which is probably the more straightforward approach if you're dealing with a Cursor as data source rather than POJOs).
I have a ListView that displays a list of items, each of which has an icon and a few bits of text.
I am making use of the "convertView" parameter of the ListAdapter.getView() method, altering an existing view rather than creating a new one when the parameter is non-null.
I had expected the ListView to recycle old views only after they had scrolled out of the visible viewport, but this appears not to be the case. It appears that the ListView is providing the same object in the "convertView" parameter on each invocation of ListAdapter.getView(). The single view is rendered to the screen, and then sent in again on the next call to getView().
This poses a significant problem for me, as I wish to modify previously rendered views. I have a background thread retrieving the icons for items, which takes "considerable" time and would be an unacceptable user interface burden to place within the ListAdapter.getView() view rendering code.
Is there any means to make the ListView not reuse views which are currently displayed on the screen? I'd like to realize the performance/efficiency gains of view reuse and be able to load the icons in a background thread.
I think you're having a similar problem I had for a while: Old items visible a while, in listview or gridview, when recycling
You have to "reset" the recycled items of the list at the beginning of getView(). Set them back to progress bar, or invisible, whatever the initial state is. Until they fetch the correct data.
I've found the issue is that Android is creating an additional, never-rendered temporary view for use in layout/measurement under certain conditions. My assumption that this view was rendered to the screen was not correct.
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).
I have an ArrayAdapter powering a ListView. I would like to change the data behind the ArrayAdapter and update the ListView's. Sounds like notifyDataSetChanged(); would be exactly what I am looking for, but it updates the entire ListView, and I would prefer to update on a row-by-row basis.
Is there a way to do this with ArrayAdapter, or do I need to manage my data some other way if I want this functionality?
It doesn't work like that, as far as I know.
It will only redraw the visible rows. This happens when you're scrolling anyway. If you're scrolling down, and one of your rows (a View) goes off the top, Android reuses it if possible when drawing rows that come into view from the bottom. This is what the 3rd parameter (convertView) of ListAdapter.getView() is for.
I'm pretty sure Android only draws the rows that you're able to see in any case.