I have an android app that loads data from a server and displays it in an endless scroll in a recyclerview.
It loads 5 items per page and if you scroll down, it triggers another 5 page to load.
Each time I scroll down, robospice is triggered and the 5 items will be cached using the current page number as the cacheKey into a SQLite database through ORMlite. The array of items returned by my server will then be added onto the total list of all items which I saved in an arraylist. This total list is then passed to my recyclerview adapter, which updates the recyclerview.
Therefore:
(cacheKey/page number:1) - first 5 items
(cacheKey/page number:2) - next 5 items
(cacheKey/page number:3) - next 5 items
Now I can also delete items on my android app. So therefore, if I don't like item 4 on page 2 for example, I can swipe left and delete it.
Since I don't keep track of the pages in my arraylist (it is a total list of everything), I can't really go:
spiceManager.getFromCache() - fetches the items from cache but since I don't keep track of the page in which the item was loaded from (remember, I load from the total arraylist), I do not have the cache key. I can't tell if the 9th item was loaded from the 2 page, for example, and therefore I don't have the cache key to fetch it from the cache.
spiceManager.removeDataFromCache() - delete the data and the associated cacheKey for those 5 items but save the 5 items temporarily into a arraylist.
spiceManager.putInCache() - I would delete the item in the temporary arraylist and then put the data from the arraylist back into cache with the same cacheKey for the 4 items as 1 is now removed
What I can do however is this:
spiceManager.removeAllDataFromCache() - remove all the data from the cache / SQLite DB.
spiceManager.putInCache() - put into cache all the data excluding the item that was previously deleted and issuing out a new cache key.
What I'm worried about with this method however, is that it is highly resource intensive. Each time you delete something, the whole DB is deleted and resaved without the deleted item.
I think that if I want to add a new item dynamically to my SQLite DB, this issue would also come about so I would also have to delete the whole DB and re-add it the whole arraylist into my SQLite and then re-issue a cacheKey.
Are there any other strategies out there for what I want to do when I want to make changes to my SQLite cache?
Thanks!
Related
I try to show data which i fetch from rest webservice (spring), in list(RecyclerView). Data can consist of thousands of rows. How should i use these data ?
should i fetch all data(or 100 rows ) and store them in local and read them from local to view in list. if i use these , how should i refresh local data ?
should i fetch 20 rows and view them , when user scroll down and arrive last item , i fetch another 20 rows ?
or should i use another way ?
If i store all data as array , it can throw outofmemoryexception . are there any tutorial or key words to search ?
How twitter or instagram use these data ? There can be a lot of items in twitter list ,but it doesn't crash and twitter can show items which downloaded before, offline(it means store data in local ,isnt' it ?)
To make app work smoother with RecyclerView, use Endless Scrolling.
Load 20 items at a time, apply pagination on your server API call.
Cache every response from server to local storage using OKHttp Response Caching.
Create a local database, store all data you already loaded inside the DB and add a "freshness" like a timestamp if your data is subject to change. If your data items are huge, consider loading an "index" of your data first, then load the individual details later.
Definitely you should not fetch all the data at once. Read about Pagination for dynamic data in android. Recycler View also uses inbuilt pagination for static data but in case of dynamic data i.e. when you are retrieving data from your api, you should send requests to your api when the user scrolls down the list to fetch the next set of data. In order to do that you'll have to extend RecyclerView's OnScrollListener and override the OnScrolled method.
We store a copy of the server state of some items locally in our app. When we get new data from the server, items may have been changed, removed or inserted. When data is synced, all current data is fetched from the server.
Local list:
Item 1, progress 23
Item 2, progress 75
Item 3, progress 88
Remote list: (item 2 was removed)
Item 1, progress 55
Item 3, progress 88
Item 4, progress 1 (NEW)
The current solution clears the table and then bulk inserts all items like this:
// Remove old content (this is to prevent dead items being left)
mContentResolver.delete(URI_TO_TABLE, null, null);
// Insert all new items
// Most existing items are changed in a sync, hence we may just insert them again instead of updating
final ContentValues[] inserts = new ContentValues[newItems.size()];
for (int i = 0; i < newItems.size(); i++) {
inserts[i] = getChallengeContentValues(newItems.get(i));
}
mContentResolver.bulkInsert(URI_TO_TABLE, inserts);
The problem here is that we also use a ContentObserver, which sends out two onChange() each time (one for delete and one for bulkInsert), causing our UI to first update when the table is cleared, emptying our list of items, and directly after update with the freshly synced list, populating the view again. This is causing a lot of ugly blinking.
Is there anyway to just get one onChange()? The applyBatch() seems to generate one onChange() per operation. Can you somehow tell ContentProvider to threat a bunch of updates as only one?
OR is there another way of basically taking the new list (remote) and store it in the database?
As you mentioned applyBatch() is the right way to do this. Create ContentProviderOperation for each of your add/update/delete transactions, store them as an ArrayList<ContentProviderOperation> operations and run them as in a single applyBatch() operation.
http://developer.android.com/reference/android/content/ContentProvider.html#applyBatch%28java.util.ArrayList%3Candroid.content.ContentProviderOperation%3E%29
If your table is huge and you do not want to have the overhead of applyBatch() and need must use bulkInsert() then you could add some sort of hack like adding a extra in the delete query would would instruct the provider to not trigger notifyDataSetChanged()
I'm having trouble building a twitter style load more button in the middle of my recyclerview. I'm currently working with a syncAdapter to fetch new data before inserting them into a db. I also have a ContentProvider and i'm using a Loader which is a CursorLoader to update the recycler_view's adapter.
When the syncAdapter fetches newer data than what exists in the app and there is more data available between the last of the new items fetched and the previous top item I want to show a LoadMore button in between.
My would-be logic for activating the loadMore button in my adapter is if the last row id of the newly fetched data set doesn't exist in the db. But the problem is I don't know where to perform this logic.
I can't make it in onLoadFinished because it is called after the new data is inserted, so I can't check the incoming data against the old data there, because by then the id of the last row in the incoming data set has already been written to the db.
I've thought of making the check while unparsing the incoming json before inserting to the db. I can check if the last id received exists in the db there, and know if a load more button is warranted, but letting the adapter know from there seems non-trivial. Since data is fetched on another thread(syncadapter or a service I've got), i'd have to write the fact that loadmore exists between two rows in SharedPreferences or send a broadcast. Is there a more elegant way of doing this, maybe i've missed something.
I'm open to suggestions.
I need to build a listview with many items.Each item info queries from managerQuery or sqlite.It has some fields: title(String), description(String), path(string). I waver between save info of list object or get info while building each item. Saving info to list object will increase ram and getting info while building each item makes app slow (my listview has large no. of items).
Querying the db every time you build new item will slow down the list scrolling. Getting data before hand is better approach.
I have a ListView which uses cursor adapter to show the records from database. When a new records is inserted in database ,it works great and shows that entry on top of ListView on requery.
Now I am facing problem when User scroll down the List, background thread call web service and brings old data. In this case when it does requery, old data is also getting appended on top of list which should append old data at the end of list.
What should i need to do differently, to add old data at the end of List rather than top ? do i need to change method of insertion when I am getting this old data ?
I think you need to store a date field in your bd table and make an ORDER BY in the query....