A few questions about SQLite database cursors in A

2020-02-09 05:16发布

问题:

To implement database access in my application I followed Lars Vogel tutorial, but I'm very confused about a couple of things...

1) Every time a call is made to fetchTodo a new cursor will be created and returned. Leaving the previous cursor for the garbage collector. So, if I don't use startManagingCursor or even the CursorLoader for that matter, should I call a .close() on the cursor when I'm done with it ? Outside of fetchTodo scope of course, example:

Cursor cursor = mNotesAdapter.fetchTodo();
// do something...
cursor.close();

I'm done with this cursor and new one will be created on the next fetch, should I close it like this then or should I leave it for the garbage collector? Although I think I'm talking about 2 things entirely different... Point being, should I close it like in the example above or not?

2) Cursor also has a .deactivate() method and the documentation says it uses less resources (than active cursors). When exactly should I use this? For instance, in my app, I have a ListActivity which is populated through a SimpleCursorAdapter (the code initialization for this is only called once). The cursor being used is a class member variable, because I need it outside the method that populates the list. I need it to requery the database when something is deleted from it. But until a record is deleted, which is a user action and may take a while to happen, should I deactivate the cursor in the meantime? Cause it will be active again when I call .requery() again. Or the SimpleCursorAdapter is going to stop working because the cursor is not active?

EDIT: I just tested this one and found out that I can't call deactivate() after setting up the cursor adapter. The list will be empty if the cursor is not active, so it needs to remain active for as long as the ListActivity is displayed. In the end, we should just let StartManagingCursor handle it then. Or the new CursorLoader.

3) I know that startManagingCursor/stopManagingCursor are deprecated but I'm not targeting Honeycomb (at least for the time being) and I don't want to deal with the new CursorLoader for now. But in the tutorial above, startManagingCursor is used everywhere, but stopManagingCursor is never called once. Why not? Does Android deals with that in it's own way? Any situation I should call stopManagingCursor?

回答1:

Edit: Updated answer to reflect updated question 1:

1) Every time a call is made to fetchTodo a new cursor will be created and returned. Leaving the previous cursor for the garbage collector. So, if I don't use startManagingCursor or even the CursorLoader for that matter, should I call a .close() on the cursor when I'm done with it ?

Yes, you should definitely either tell Android to startManagingCursor(), use LoaderManager/CursorLoader or close() it yourself. Not doing so will leak memory, the GC won't help with that as there's native resources behind the Cursor (e.g. file handles to the database).

2) Cursor also has a .deactive() method and the documentation says it uses less resources (than active cursors). When exactly should I use this? ...

EDIT to other readers: The OP found an answer and posted it in his question. The following still holds:

I've never used deactivate() (there's no deactive()), maybe someone else can explain this. If you want really painless requery/updates, do check out the LoaderManager framework -- it's not only for Honeycomb: using the compat library you can use LoaderManager (and Fragments) down to Android 1.6. Not only is it less code for you to write, but it completely offloads these things to Android, much more so than startManagingCursor().

EDIT2: Some notes on LoaderManager

There are LoaderManager tutorials on developer.android.com but these are quite... complex and hard to understand the first time like most of the tutorials there. I also had to dig a lot, the best all-in-one stop I found so far is http://mobile.tutsplus.com/tutorials/android/android-sdk_loading-data_cursorloader/ (plus all the javadocs and compat lib source you can find) --- the way LoaderManager works is very similar to the (now also deprecated, replaced by DialogFragment) managed dialogs with their onCreateDialog, onPrepareDialog methods where you just tell Android to "show dialog #123" and then Android calls your code with that ID; same for loaders: "load loader #123", Android calls on onCreateLoader().

The only obvious drawback is initially, that LoaderManager relies heavily on the ContentProvider framework and some people seem to really dislike that. Sure, it's additional learning and code, but once you have a ContentProvider for your own data (even if only used privately in your app), all the data-to-view bindng is a breeze with CursorLoader. IMHO, there's little difference between rolling your own "content provider" and actually implementing the ContentProvider -- but this is just my highly controversial opinion :)

3) I know that startManagingCursor/stopManagingCursor are deprecated but I'm not targeting Honeycomb (at least for the time being) and I don't want to deal with the new CursorLoader for now. But in the tutorial above, startManagingCursor is used everywhere, but stopManagingCursor is never called once. Why not? Does Android deals with that in it's own way? Any situation I should call stopManagingCursor?

Once you call startManagingCursor() the Cursor is no longer your problem. Android will take care of closing the Cursor when your Activity gets destroyed (user navigates away, orientation change, ...). There's no need to match a call to startManagingCursor() with a call to stopManagingCursor() -- you usually don't want to take on the burden of managing a Cursor again once you've gotten rid of it.