In the beginning we had listViews. As a developer, we had to recycle and reuse the views to have a fluid experience.
Then, came the recylclerviews. Now, all the recycling heavy lifting is managed by android library itself.
Using pagination, an infinite recycler view can be implemented, which loads the data when needed.
But there is one problem I am still facing in infinite recyclerview. How is the data in the adapter managed?
In most of the infinite scroll implementations of recyclerview, the new data is appended to the original data. This makes the size of data set ever increasing.
Why cant dataset itself behave like recyclerview and recycle its data, instead of appending? (Like a circular queue).
How can one manage the positions of itemviews, when the dataset is a circular queue. Is it unnecessary and yields too little performance improvement? Am I missing some design pattern?
It would be possible to clear data already loaded, but this way you have to load data not only for "bottom" views, but for "upper ones" too. So user wants to back to previous data and he needs to load that data again, that's the problem.
There could be more work about notifying data set changed in recyclerView.
You can implement it this way, but remember about pagination and how it is implemented - for example limiting data in SQL statements standard way can output different data each call, so user backing to previous data can see other results! Check Twitter pagination for one of the way to achieve same results each time.
Pros:
less data in memory
Cons:
more work to write the code
more data loading for users (more internet usage, more loading times - when users wants back to previous data)
pagination has to be designed more carefully
Related
I am using the Paging library from Android Jetpack to have a paged loading behavior in my RecyclerView. I'm loading directly from network so I don't have any intermediate in-memory cache or database. Whenever something changes I call invalidate() on DataSource (in my case PositionalDataSource) so that the list is refreshed.
What I need is very simple thing - once I call invalidate() the recycler view is fully cleaned up and shows empty data. I need the recycler view to keep the old data and update normally once the new data comes in. In most of the cases the update might be very small, like a button color change in couple of rows, it looks ugly when the RecyclerView shows empty content for couple of seconds while I'm loading data from backend.
Can this somehow be done or is there a conceptual limitation of the current Paging library architecture forcing me to implement my own caching?
calling notifyDataSetChanged instead of invalidate may help as a simple solution.
List data is to be displayed in a RecyclerView, and a graphical view at the same time. It is my understanding that separate adapters would be required for each.
My issue is
I've been struggling with where to load persistent data and hold it at runtime.
Loading and holding the data in separate adapters means loading the same data twice from persistent storage. Although some might be cached, it is still effectively loaded twice.
How to trigger update of both views when the data is changed, say from an activity launched from click on the list view?
The views should not need to know about the existence of each other.
Maybe the simple(?) solution is to wrap the list in a class, which handles the data loading, giving it an interface for listeners (the adapters) to subscribe to, and add the necessary listener interface, implementation, etc.
I don't mean this to be an opinion oriented question. There should be a common or best practice method. I'm new to android development.
I have a ListView/RecyclerView. Now, I want to add more information for each item and the information could be found in database according to the item value. How would you guy achieve it??
For the best practice, should I query database in the background thread? Should I cancel the query if user scrolling fast?
There is no "best practice" AFAIK, but the following is a short summary of your options:
Query on UI thread as the user scrolls
It is usually a very bad practice to execute queries on UI thread in general. It is a sin to do this in ListView.
That said, there are ORM libraries that perform lazy loading of nested objects on UI thread (e.g. GreenDAO). People use these libraries in applications that have ListViews and it even works alright for some of them.
I would strongly advice against this method.
Query of all items ahead of time
As #CommonsWare mentioned, for small to medium collections you can just load the entire dataset into memory on background thread and then bind it to the ListView. You will need to show some kind of progress indication while the data is being loaded.
The definition of "small" and "medium" is very vague, but I'd say that if you are sure that the dataset will not be larger than few MBs, then this method can work pretty well.
The drawback of this method is that the user will need to wait for the entire dataset to be loaded and bound to the ListView. Depending on the size of the dataset and the complexity of database scheme this might take a while.
Query a predefined number of items initially, and then perform additional queries as the user scrolls
This is the most complex scheme of all, but it is inevitable in some cases (e.g. "infinite list").
The idea is to get some predefined number of items into the ListView, and then track user's interactions in order to supply additional items.
For example, you can fetch 100 items initially, and then fetch additional 100 when the user scrolls to the end of the list.
An optimization of this scheme would be to fetch additional items before the user gets to the end of the list (let's say when he scrolled through 50 items). This allows to create a truly "infinite list" behavior.
Note that if your collection is very large, you will need to take care not only of adding a new items as the user scrolls, but also of removing "previous" items in order to avoid out of memory crash.
Query of additional information for items that are already shown
Sometimes you would like to perform some additional query after the item is already shown.
In this case, just perform the query in the background and bind the data to the item.
One caveat of this task is that if the view of the item is recycled (as is the case in RecyclerView by default), then when your background fetch is done the target View might show totally different item. Binding the returned data to this View would be a mistake.
One way of handling this is to cancel the fetch. However, this is cumbersome and error prone in practice.
The easier way is just set transientState flag when the query is initiated, and clear it when the query is completed.
Today I was thinking about how Android framework works, and I'm not sure about one thing - how developer (me) should program lists to show custom data from few sources. I created few apps, but its important to me to keep my applications clean and fast as possible.
So - I have an app, for example news reader. Im using Fragments, ListFragments, custom layouts for list items and BaseAdapter for showing data in many lists and activities. Nothing new here, and nothing special. At first I download all data from webserver to sqlite in app, so Im sure about it speed and stability. And then what's next?
Should i create List items from Java Lists (List items) and then pass it to baseadapter, or I should only use way SQLite Cursor->list item? What is better to refresh list, add new items and delete them? Remember that i have my ListFragment with baseadapter in separate class.
Im not sure about it, so I clearly dont know how should i refresh and load new items to my list. I just want to keep app clean, without many 3rd party libraries (so i dont care about EndlessList or something like that).
tl;dr
How should I create list for speed purposes, when i use few sources to show data?
I'm not sure whether I understand your full question but about the part which data source to use for an Adapter, here are my thoughts:
I think that depends on the amount of data you are dealing with. If it is sufficiently small you can keep everything in a List in memory, but you also need to be sure that the data won't grow over time.
Using a Cursor as a data source is unfortunately also not a safe option for getting around a possible "Out Of Memory" exception problem. There is a limit per query because of the implementation of the cursor which apparently loads the whole result set into memory.
So if you are dealing with a lot of data or data that potentially grows over time (like messages, user-created items), you need to have an Adapter that internally works with a data window which loads a fixed amount of items into memory at a time. That window always keeps a bunch of items in memory which can be currently viewed and quickly reached with the ListView (by scrolling up and down).
Let's say that window holds for example 200 items.
When the upper / lower bound of that window is reached the Adapter needs to load the next adjacent window. You can observe that kind of behavior in the GMail app ("Loading conversations....").
I would let that data sit in the cursor and not transfer it to a list first, because you can use the cursor like a list.
When I have a ListActivity and an Adapter how does Android handle a list with 200 elements.
Does it try to load all of them directly how does it wait till the user scrolls and then renders those elements?
Do I have to worry with performance when a list is too long?
Depends how are the adapters implemented.
If you have an adapter that is not subclassed (you use one that is provider by SDK) Android will try to load all of them directly.
I recommend to subclass SimpleCursorAdapter and implement your custom adapter. This way you will have for example 10 views (as many your screen needs), and the view it will be reused for the rest of the 190 records.
There are several parts to this question. First of all, the data itself. Is that coming from a SQLite database via a query? If so, you have a Cursor object, which contains the entire result. So if you have a query that yields 200 rows, you will have all 200 rows in memory (which is why it's so important to narrow your projection).
As for the list itself, that part is pretty efficient - Android will only create views for the elements that you can actually see. And, depending on what kind of views you have, and whether they support recycling, Android will actually recycle existing objects to minimize the amount of overhead for initialization and memory management.
I'm not sure how Android handles it internally. But most programs I've seen handle the issue by loading 20 or so items and then making the last item say "Load next 20 items". Then when you click it, it loads the next 20 items.