When to close Cursor used in SimpleCursorAdapter
Asked Answered
A

4

13

I'm using a SimpleCursorAdapter to display results in a ListView but since I've got to query my database lots of times during a search (using the SearchView widget) it worries me that the cursor might be left opened.

This is how I query my database and show the results in a ListView:

class SearchCustomers extends AsyncTask<String,Void,Cursor>{

        @Override
        protected Cursor doInBackground(String... params) {         
            //get the query
            String query=params[0].toLowerCase(Locale.getDefault());
            Cursor cursor=mDB.searchCustomersByName((query != null ? query : "@@@@"));
            return cursor;

        }

        @Override
        protected void onPostExecute(Cursor result) {           

            if (result != null) {

                String[] from = new String[] { QuickOrderDB.ID,
                        QuickOrderDB.NAME,
                        QuickOrderDB.ADDRESS,
                        QuickOrderDB.PHONE_NUMBER };

                int[] to = new int[] { R.id.customerIDTextView,
                        R.id.customerNameTextView,R.id.customerAddressTextView ,
                        R.id.customerPhoneTextView };

                SimpleCursorAdapter cursorAdapter = new SimpleCursorAdapter(SearchCustomersActivity.this,
                        R.layout.results_customer_item, result, from, to);
                mResultsListView.setAdapter(cursorAdapter);                 

            }
        }           

    }   

I have tried many things to close the cursor, but even If I close it after mResultsListView.setAdapter(cursorAdapter); the result is always the same: an empty ListView.

I've already seen a couple of questions in which it is mentioned that the cursor will be closed automatically, but I want to make sure this is true.

Is there any official documentation about this? Does the SimpleCursorAdapter really close the cursor automatically??

Thanks in advance.

Adonic answered 30/9, 2014 at 20:3 Comment(13)
Typically you would close it after its use and then grab another later when you need it again.Resident
but even if I close the cursor after this part mResultsListView.setAdapter(cursorAdapter) the ListView won't display anythingAdonic
Typically you would call notifyDataSetChanged on adapters in order to be sure that the information they are constructed with at a later given point in time is updated on the screen. But there might be something else you have missing in your structure.Resident
The only thing that worked was not to try to close the cursor. But since mDB.searchCustomersByName is called for every letter the user types in, it worries me that I might be causing a memory leakAdonic
if you close it after calling setAdapter, then the adapter won't have any data to get, as the cursor will be closed. close it when you don't need it anymore. hint: as long as you are displaying data from the cursor, you need the cursor open.Wangle
typically if you call swapCursor(?) on the adapter, the old cursor is closed.Wangle
So how will I know when I don't need the cursor anymore? I guess this will be when I leave the Activity, but I suppose I'll have to keep a reference to the Cursor thenAdonic
The simpleCursor adapter is supposed to do the closing for you. You can find more info by researching loaders. developer.android.com/reference/android/app/…Closestool
@Closestool so there's no need to use startManagingCursor then. Will LogCat warn me If any cursor is getting leaked??Adonic
@Adonic Did you find any solution to this problem? I've got the same issue and I haven't been able to find any documentation either :SBurp
Nope :( The closest reference I've got is the provided by @ClosestoolAdonic
I'm not closing cursors when the are used with a loader. IDK if I'm wrong.Closestool
I think the solution is in mutating the List inside the adapter (by extending the class) instead of creating multiple adapters.Lanciform
A
6
  1. You need to close your cursor once you are done with it. Closing it after setAdapter() call would prevent the adapter from accessing the data. Hence a better place to close the cursor would be during current activities tear down life cycle stages such as onPause() or onStop(). (onDestroy() should not be used as Android run-time does not guarantee calling it. I think on latest version onStop() is guaranteed)
  2. I don't think SimpleCursorAdapter adapter automatically closes the cursor automatically. The official document mentions that changeCursor() automatically closes the old cursor, so another option could be to change your cursor after search. http://developer.android.com/reference/android/widget/CursorAdapter.html#changeCursor(android.database.Cursor)
Andras answered 10/5, 2015 at 5:6 Comment(0)
M
2

It's better if you get the Cursor using a CursorLoader instead of an AsyncTask. The Loaders are synched to the Activity/Fragment lifecycle via the LoaderManager, and the system will close the Cursor provided by the CursorLoader automatically for you when it's needed.

Millipede answered 10/11, 2016 at 12:10 Comment(0)
A
0

You should close the cursor in your fragment or activity's onPause() callback. After the activity is paused it's possible that older Android systems will delete the app to free memory.

This implies that you need to reestablish the cursor in the corresponding onResume() callback.

Apothecium answered 10/8, 2016 at 6:41 Comment(0)
W
-3

Don't create a variable for the cursor, just add the db query directly into the constructor as the argument c, db.query() or a method that holds the desired query), this seems to work.

SimpleCursorAdapter (Context context, 
                int layout, 
                Cursor c, 
                String[] from, 
                int[] to, 
                int flags)
Warden answered 27/9, 2016 at 20:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.