When not to use CursorAdapter for ListView - android

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.

Related

How to use ContentObserver with RecyclerView?

With ListView we have had a good native pattern to map some data from db to list:
DB -> ContentProvider -> CursorLoader -> CursorAdapter -> ListView
This approach was good in terms of data layer separation, performance and automatic data updates. But this pattern doesn't really fit new RecyclerView. There are some approaches to mimic old behavior:
Using the recyclerview with a database
But there is a problem with using old style notifyDataSetChanged with RecyclerView. It can't use ItemAnimator features, it loses scrolling position, and it's just ineffective.
So, how we can benefit from finegraned change notifications while using DB wrapped in ContentProvider? Cursor is static, and to get new data from it we need to get new Cursor. So, it seems that we will need an custom intermediate data layer, which will merge data from Cursors and expose the List of entities to RecyclerView.Adapter. Also, we will have to manually map ContentObserver onChange() events to RecyclerView notifications. This also means that we will have to get rid of CursorLoader. That is an incredible amount of work for such basic task.
Is there any better solution?
You can use the DiffUtils class to compute the differences between the old and new cursor.
When using it you just need to implement two methods :
areItemsTheSame() to know if two items represent the same logical item (even if the content is different). Usually you would base the answer on an identifying field of your item;
areContentsTheSame() to know if two items representing the same logical item have unmodified content.
Once the differences are computed, you can then just apply it to your adapter and it will automatically call the notifyItemChanged(), notifyItemInserted() or notifyItemRemoved() accodingly.

CursorLoader with Cursor accsss inside a loop

I'm building a ListView, and each item in the ListView has data from several different Cursors. I've got an object which holds all the data for each item in the ListView. I'm using an ArrayList of these objects to populate the ListView.
The way I'm implementing it now, I first get a Cursor to all the rows in ContentProvider A. I loop through this cursor, adding three of it's fields to each object in the ArrayList. On each iteration of this loop, a new cursor is created to pull a field from ContentProvider B based on a field in ContentProvider A. This field is used to pull another field in ContentProvider C. So, essentially, there's lot's of Cursors being created, and the queries of subsequent Cursors are dependent on data from previous Cursors.
From what I understand, it is ideal to use CursorLoaders and LoaderManager to generate the Cursors in a separate thread and manage their life cycle correctly. I'm not sure how to translate this approach, or if there is in fact a better approach that minimizes the number of Cursors in the first place.
I think a simple CursorLoader is not the right solution in this case. I think you might have two possibilities:
Use a CursorLoader for the first Cursor and use CursorLoader-chaining within your ListAdapter's getView() method. With CursorLoader-chaining I mean calling initLoader() in your onLoadfinished() method.
Use an AsyncTaskLoader and create within your AsyncTask the object tree you need.
Of these two solutions I think the second is probably the better one - unless the list is very long. This is one area where ContentProviders fall short. You basically have to query n+1 (in your case n+2) times where one join should suffice.
If your list is very long, the second approach is not usable, your AsyncTask would take too long for users to accept it.
Should you ever hear of (or find yourself) of a better solution, please ping me here.

Loading a BIG SQLiteDatabase in a ListActivity

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.

BaseAdapter vs CursorAdapter

I would like to know when to use each Adapter. According to my experience, and this article BaseAdapters are useful when I am getting data from an API for example, and I store it in a Collection object.
However a CursorAdapter is used to query contents from a database, phone agenda...In general, contents which have also a content provider to query the info out of them.
So basically a BaseAdapter is used to queries that dont have a content provider to access them, because in that case a CursorAdapter will be the best choice. Is that right?
BaseAdapter,ArrayAdapter,SimpleAdapter etc are mostly used if you are getting dynamic data from a remote connection (like a web service or API) and can be modified as your wish.
CursorAdapter is mostly used for local files or database to query the database and the content of it.
In your case CursorAdapter seems like the one to go.
#serdar explaination is almost right, if you are dealing with any database either your own or device(like contacts, sms etc) CursorAdapter is used, and if you want to make your custom list with Images and Textviews etc, then BaseAdapter is generally used. Any if your dealing with more complex custom listview like sorted contacted list along with seprater like A,B,C... then you have to use EfficientAdapter.

Android listing design problem with cursors

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.

Categories

Resources