I am in a situation where I will probably need to manipulate two separate Cursor objects. I was hoping there was someway to create our own Cursor by combining two separate ones. But I am not sure if it is even allowed. Read somewhere you can't, but I wanted to devote a specific question to that so it is at least given some attention for others who have a similar situation.
I was hoping there was someway to create our own Cursor by combining two separate ones
Have you tried MergeCursor? Quoting the documentation:
A convience class that lets you present an array of Cursors as a single linear Cursor. The schema of the cursors presented is entirely up to the creator of the MergeCursor, and may be different if that is desired. Calls to getColumns, getColumnIndex, etc will return the value for the row that the MergeCursor is currently pointing at.
Also, if your objective is to display both Cursors in some form of AdapterView, you could use my MergeAdapter and concatenate things at the Adapter level
Even if you found a solution for your concrete use case, i would still like to answer your main question.
Yes it's possible to implement your own cursors.
Cursor is a public interface and can be implemented by everybody.
It has, however, a large amount of methods that need to be implemented.
Using AbstractCursor or AbstractWindowedCursor as base class can help to reduce the overhead.
The available concrete implementations can be extended, too.
CrossProcessCursor, CrossProcessCursorWrapper, CursorWrapper, MatrixCursor, MergeCursor, MockCursor, SQLiteCursor
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.
Why is setValueAt(...) in the public interface of the SparseArray class? I was using it instead of put(...) obviously not getting the result I had in mind.
I came here trying to figure out the same thing. As Prekak Sola mentioned in the comments, setValueAt maps a value on a specific index, while put maps a value on a specific key.
Obviously, that can become confusing, but I think it is a very useful feature, because if you look at the official SparseArray documentation, it is mentioned that the SparseArray is generally slower than a HashMap, because lookups require a binary search and adds and removes require inserting and deleting entries in the array.
So, I guess that in certain cases, it would perform much faster if you iterate over the items in this container using keyAt(int), size(), and obviously all index-related functions, such as setValueAt, instead of using the keys.
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.
I have been creating Spinner controls (Combo boxes/Drop downs) in one of my apps, and was surprised to find out how difficult it was to achieve all of the following features:
User facing Strings are externalized, taking advantage of strings.xml internationalisation (I18N) feature of Android.
Spinner selections operate using a System view, which facilitates not having to work with or map Strings to meaningful values (yuck).
User view to System view mapping should be easy, automated and minimal (i.e not hand rolled for every component).
Others have attempted solutions to this, but universally as far as I could see they suffer from one or many of the following problems:
UI code is creeping into their enum class which doesn’t belong there (messy), nearly all existing solutions suffered from this.
Hardcoded User facing Strings in their enum classes. Because these are not externalized you cannot do I18N using the stock Android features.
Authors typically make the Fragment or Activity an OnItemSelectedListener which perpetuates a common problem of inheritance for convenience, where composition is more appropriate.
I have developed my own solution which does this: http://www.androidanalyse.com/android-spinner-externalize-user-strings-mapped-to-system-enum/
My question is, have I missed something? This seems like something that should not have been this hard (which makes me feel like I'm possibly reinventing the wheel).
Below is some example code showing my solution in-use (which is available Apache 2 license from the link above).
String none = getString(R.string.none);
String light = getString(R.string.light);
String medium = getString(R.string.medium);
String strong = getString(R.string.strong);
SpinnerUtil.createNewSpinner(view, R.id.wind, Arrays.asList(none, light, medium, strong), WindLevel.values(),
new SpinnerItemSelectedListener<WindLevel>() {
public void onItemSelected(Spinner item, WindLevel value) {
// Take whatever action you wish to here.
}});
I would just use ArrayAdapter<WindLevel>. Yes, you created a custom typed listener, but the regular event listener gets the position and can call getItem() on the ArrayAdapter<WindLevel> to get a WindLevel properly typed.
IMHO, the vast majority of Spinner widgets will be populated with material read in from a database, the Internet, or some other dynamic data source, rather than populated by some sort of enum with display values coming from static strings that can be internationalized ahead of time.
This is not to say that your code is useless: if you find it useful, then it was worth writing. And I am sure that there are apps out there that contain your targeted pattern (i.e., a Spinner backed by an enum or equivalent where the display values are known in advance and can be internationalized) who might find your solution useful as well. Every developer who writes enough code cooks up these sorts of helper classes and the like that help map an OS or framework model into something that better fits the developer's own mental model. So long as you are not perceiving any performance issues, it's all good.
Also, note that OnItemSelectedListener is an interface; implementing that interface on an existing class is not inheritance.
I believe the reason nobody answered you is :
What problem are you trying to solve ? Spinners existed prior to your well designed attempt.
Why reinvent them in exactly the same way they exist in Android ?
http://developer.android.com/guide/topics/ui/controls/spinner.html
It is a beautiful wheel indeed you designed, but still, it is just a wheel :)
UPDATE :
I think I begin to understand what you did. This is interesting. I'm not sure why you did not go to the pattern implemented by the ListPreference with its entries and entryvalues.
In fact, I'm not sure I understand why the Android team did not go that route either.
In any case, it is worth proposing your idea to the Android framework. It is after all open source.
I am new to android development and I've hit a hurdle when trying to load SQLite data to populate a ListFragment. In previous versions of android one made a new instance of the cursor class, made an SQLite query to place the cursor in the appropriate position, called startManagingCursor, made a new SimpleCursorAdapter and finally called setListAdapter. Pretty darn simple (too bad about the UI thread)!
Now almost all of these methods are deprecated and I have no idea how to populate my poor ListView. The documentation says I should use CursorLoader but here on StackOverflow people advise against using it for SQLite queries. How do I tell my cursor to populate the ListView?
Thanks a lot in advance!
You need to convert you DbAdapter into a Content Provider if you want to use CursorLoaders. and put android:exported= false as a property of your content provider so that it is private. Android team is favoring this approach as they say Content Provider is better suited to handle logic. That is why they are bent on deprecating our old ways( was hard on me too). But I have changed my dbadapters to content providers and now gleefully using cursor loaders( they are too cool not to be used). Try it, generally you will do fine with some more boilerplate code of Content Providers in adition to that of DBadapter and sqliteHelper. GO for it!