EDIT the assumption of this question is wrong, Android doesn't keep the query open, but it can cause other problems. See discussion bellow...
The Android Cursor implementation keeps a scrolling window of the underlining SQLite cursor, so it can implement "move forwards".
But I found a old SQLite documentation saying this is a bad practice, and you should not leave query open for UI inputs:
https://www.sqlite.org/cvstrac/wiki?p=ScrollingCursor
Also for example Telegram use it's own wrapper of SQLite, and don't have the scrolling cursor. https://github.com/DrKLO/Telegram/blob/master/TMessagesProj/src/main/java/org/telegram/SQLite/SQLiteCursor.java . They only have "next"
Also there is the "best practice" to call "getCount" in CursorLoader, if you look at the implementation, it actually tries to loop through all the data in the underlining query.
So is Android's wrapper implementation bad? Is SQLite doc outdated and it is ok to keep query open?
The Android Cursor implementation keeps a scrolling window of the
underlining SQLite cursor, so it can implement "move forwards".
Both scrollable and non-scrollable cursors implement move forward, i think you meant move backward here.
The documentation you specified, doesn't tell that using scrollable cursor with UI is a bad practice. It says
Get in, grab your data, then get out. Later on, when the user decides
to scroll up or down (which will usually be eons of time later from
the point of view of your CPU), run another query to refresh the
screen with new data.
As far as I know, android cursors work exactly this way. Android's SQLiteCursor (that is actually used with SQLiteDatabase class) is a subclass of the AbstractWindowedCursor. AbstractWindowedCursor uses CursorWindow within it, that is, as per documentation:
A buffer containing multiple cursor rows.
Each time the limit of this buffer is reached, AbstractWindowedCursor makes new CursorWindow and fills it with data.
P.S. In fact, these windows keep fairly big amount of data. It,s not limited by the screen size and far more than 5 or 50 rows (to be precise, it can be limited by 5 or even 1 row, if your rows contain, say, a thousand columns), and we as developers rarely face such behaviour.
Related
I've heard from my friend that CursorAdapter does not follow the MVC rule, it take the values directly from Database to the View, not through the Model. Furthermore, he said everytime user iterate items via list view, CursorAdapter execute dbs query again and again. As a result, CursorAdapter will not be used frequently.
I'm very curious about this statement, anyone can help me out? Is he right or wrong? And if he is right, what Adapter I can use instead?
CursorAdapter... take the values directly from Database to the View, not through the Model
That depends on what you define your model to be. The Cursor could be the model, for trivial apps, in which case CursorAdapter takes data from the model and applies it to the view.
Your friend may be thinking of a model defined as a set of custom Java classes; in that case, CursorAdapter would know nothing about those classes.
he said everytime user iterate items via list view, CursorAdapter execute dbs query again and again
Not really. CursorAdapter knows nothing about executing database queries.
The only scenario that I can think of that resembles what you friend describes is if your query has a large result set, over 1MB. In that case, the Cursor will not hold the entire result set, the way it normally does. Instead, it holds a portion of the results, and if the user scrolls past what the Cursor holds, the Cursor will trigger database I/O to fetch more results (and let go of some past ones, to minimize the overall amount of memory held by the Cursor).
As a result, CursorAdapter will not be used frequently
I would say that it is less frequently used than is ArrayAdapter, and both are falling out of favor in general, as more developers move to RecyclerView and RecyclerView.Adapter.
I think what your friend really is concerned about is using a Cursor as a model, as opposed to having a "real" model (and perhaps view-models) as part of an MVC/MVP/MVVM architecture. Certainly what I hear from larger projects indicates that a Cursor is mostly used for populating other model objects, rather than being used by a CursorAdapter or RecyclerView.Adapter directly. But, it really depends a lot on the app. Trivial apps do not need strict adherence to some specific GUI architecture, and the dividing line between "trivial apps" and "larger projects" is difficult to define.
And if he is right, what Adapter I can use instead?
If your friend wants model Java objects, typically you would use an ArrayAdapter or a BaseAdapter that knows how to get at the collection of model objects. Or, in the RecyclerView realm, you would use a RecyclerView.Adapter that knows about the structure of your collection of model objects.
I'm new to android dev (xamarin) and trying to undestand the basics. So as you scroll through a list, does it hit the db as you go, or does it pick up rows from a cache.
-If it does hit the db, why would most docs say that it is more efficient than say supplying a base adapter with an ilist. At least this way I only hit the db once.
-If it doesnt and puts everything in a cache, then its similar to using a base adapter with supplied with a full list.
I'm still confused as to why most people say the cursor adapter is more efficient ?
Thanks,
Mick
No, it caches the full result.
If anyone wants to find out more about CursorAdapter he can look here: https://developer.xamarin.com/guides/android/user_interface/working_with_listviews_and_adapters/part_4_-_using_cursoradapters/
I'm working on an Android project I need to finish very fast.
One of the app's features is loading a SQLite database content and listing it in a ListView inside a ListActivity.
The database contains a few tables, among which 2 are very large.
Each item in the database has many columns, out of which I need to display at least 2 (Name, Price), although preferably is 3.
This might seem a pretty easy task, as all I need to do in this part of the app is read a database and list it. I did this without any problems, testing the app versus a small sample database.
In my FIRST version, I used a Cursor to get the query, then an ArrayAdapter as the list's adapter, and after the query I simply loop the cursor from start to end, and for each position I add the Cursor's content to the adapter.
The onItemClickListener queries the database again versus other parameters (basically I open categories) so it clears the adapter, then loops the Cursor and adds its content to the adapter all over again.
The app worked like a charm, but when I used a real-life, big database (>300MB) I suddenly got my app taking very long to display the contents, and sometimes even blocking.
So I did some research and started using a SimpleCursorAdapter that automatically links the contents of a Cursor to the ListView using the usual parameters (String[] from, int[] to etc., where I used android.R.layout.simple_list_item_2 and android.R.id.text1 and text2).
Problem is, is doesn't change much the time to load.
I've came across some suggested solutions on different web sites and tutorials, most of them using, in one way or another, the AsyncTask class. I tried implementing this manually myself but it's hard to keep track of multiple threads and I failed.
Tutorials keep telling how to do this with content providers, but I found nothing clear bout my specific situation: very big SQLite database -> read to ListView.
Now my head is filled in with notions like LoaderManager, LoaderAdapter etc, all mixed up and confused in my head.
Can anybody please provide me a complete, nice, clean solution to do this "simple" task?
Again: I want to read a BIG SQLiteDatabase and display it in a ListView. I want the app NOT to block.
I need a class that has a member function that takes as parameter a query and the ListActivity's context and takes itself care of displaying the result of the query in the view.
Please don't provide me abstract answers. I'm running out of time and I'm very confused right now and I need a clean complete solution.
You're my only hope.
If you query such large database it will take tym, you need to find a smart way,
Like limit you database query to get first 10 or 30 items and then maintain,once last item is reached query rest 30 items and bind them
Refer this tutorial, it will teach you how to add data dynamically in a list view
http://p-xr.com/android-tutorial-dynamicaly-load-more-items-to-the-listview-never-ending-list/
The above list has expired chk this
http://mobile.dzone.com/news/android-tutorial-dynamicaly
If you query large database it will take time to fetch data and show it on List View. So it is better to populate data at run time. You can use Lazy Adapter concept to load data . This link1 may be useful for You.
Thanks
you can also use :
public class TodosOverviewActivity extends ListActivity implements
LoaderManager.LoaderCallbacks<Cursor>
check this link for more details.
I am writing an Android app (targets at Android ver 2.1 up). I am using an ExpandableListView with a SimpleCursorTreeAdapter. I find that it would crash follow this sequence:
The ExpandableListView starts up empty (i.e. no corresponding records in the database).
Record(s) are added.
Return to the screen with the ExpandableListView. Now, group(s) are shown.
Click on the group to expand, the activity will be forced close.
After days of Internet searching and then painful tracing of my application's source and then Android's platform source, it seems that the problem is: when the Android platform initiates Ithe SimpleCursorTreeAdapter, it would store the list of children fields in private member mChildFrom once during instantiation and (strangely) ON CONDITION THAT if there is at least one group. If there is no record (and therefore no group), the list of children fields are not stored. When records are added subsequently and when expanding group to shown children rows, the ExpandableListView will crash because the private member mChildFrom is null.
So, my get-around right now is: only instantiate the SimpleCursorTreeAdapter if there is relevant record in the database. If not, retry the instantiation during OnResume().
It would be helpful to me (or other poor guys having the same problem) if anybody has better reason for the crash, or has better solution. (I incline to believe that it is a bug in the Android platform.)
Try the following. Instantiate the adapter in onCreate() but pass null as cursor argument. In onResume() you then create new Cursor and pass it to the adapter using the changeCursor(). By this you always get a new cursor whenever you change anything (add, delete, edit row) on you data model.
I have a following situation in my android app.
I have an app that fetches messages from inbox, sent items and drafts based on search keywords. I use to accomplish this by fetching cursors for each manually based on selection by user and then populating them in a custom data holder object. Filter those results based on given keywords and then manually render view with respective data.
Someone suggested that I should use a custom Cursor adapter to bind view and my cursor data. So I tried doing that. Now what I am doing is this:
Fetch individual cursors for inbox, sent items and drafts. Merge them into one using Merge cursor and then pass that back to my CursorAdapter implmentation.
Now where or how do I filter my cursor data based on keywords; because now binding will ensure that they are directly rendered to view on list. Also, some post fetching operation like fetching sender's contact pic and all will be something that I do not want to move to adapter. If I do all this processing in adapter; it'll be heavy and ugly.
How could I have designed it better such that it performs and the responsibilities are shared and distributed.
Any ideas will be helpful.
Using cursors and adapters does not work out well for the most part. Our experience as led down a different technique.
Your best bet is to "pump" the cursors in an AsyncTask into an ArrayList<data-holding object>, then you can do processing and then sort that list as necessary with Collections.sort() and the Comparator of your own construction, and then use ArrayAdapter to present the resulting list. This releases cursors ASAP and stays off the UI thread while doing it and you can sort however you feel like.
Remember always process in the background and avoid ANR!
We use this in all of our apps (14 on The Market) and it works like Butter.