The cursor is finalized without first closing () in the ListFragment

I get this error message after closing the application or just letting the phone sleep with opening the application.

When I let the phone sleep, I get 30 to 61 log entries of this error message. An error is logged immediately before the ListFragment is loaded. I suspect the fragment is loading, but the error is logged before the fragment information entries.

When I close the application, I get only 1 error record, which is logged immediately after calling onLoaderReset (). I close the database before closing the application, which seems to help.

The application works, but I'm worried that it will work with a different phone.

I cannot explicitly control the cursor except adapter.swapCursor (null) in onLoaderReset ().

I appreciate any ideas on how to resolve this error.

thanks

public class ChildList extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor>, DatabaseConstants, GoodiList { private final String TAG = "ChildList"; // database columns that we will retreive final String[] PROJECTION = new String[] { CHILD_ID_COLUMN, CHILD_NAME_COLUMN }; // selects all final String SELECTION = null; SimpleCursorAdapter adapter = null; private ListParent parentActivity; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.e(TAG, "on Create"); String[] fromColumns = { CHILD_NAME_COLUMN, CHILD_ID_COLUMN }; int[] toViews = { R.id.name_column, R.id.id_column }; adapter=new SimpleCursorAdapter( getActivity(), R.layout.child_list_entry, null, fromColumns, toViews, 0 ); setListAdapter(adapter); getLoaderManager().initLoader(0, null, this); Log.i(TAG, "finished on Create"); } public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); LongClickListener longClickListener = new LongClickListener(); getListView().setOnItemLongClickListener(longClickListener); } @Override public void setListAdapter(ListAdapter adapter) { super.setListAdapter(adapter); } @Override public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) { Log.v(TAG, "starting on create loader"); Uri CHILD_URI = ChildContentProvider.CONTENT_URI; CursorLoader cursorLoader = new CursorLoader(getActivity(), CHILD_URI, PROJECTION, SELECTION, null, null); Log.v(TAG, "finished on create loader"); return cursorLoader; } @Override public void onLoadFinished(Loader<Cursor> arg0, Cursor newCursor) { adapter.swapCursor(newCursor); if (newCursor != null) { int rowCount = newCursor.getCount(); Log.v(TAG, "--- onLoadFinished: got " + rowCount + " children"); } } /** * this used to delete. However, we need it to select usually. Now delete is * done by long click. */ @Override public void onListItemClick(ListView l, View v, int position, long id) { super.onListItemClick(l, v, position, id); // delete child - remove child from list and database Object item = l.getItemAtPosition(position); Cursor cursor = (Cursor) item; int nameCol = cursor.getColumnIndex(CHILD_NAME_COLUMN); int idCol = cursor.getColumnIndex(CHILD_ID_COLUMN); final String name = cursor.getString(nameCol); final int childId = cursor.getInt(idCol); Log.i(TAG, "selected " + name + " id: " + childId + " at position " + position); cursor.close(); parentActivity.listItemSelected(this, position, childId); } /** * Forces cursor to requery database and list to be update. Used when a new * child is entered in parent activity EditText field. */ public void notifyDataChanged() { Log.i(TAG, "told adapter that data changed"); getLoaderManager().restartLoader(0, null, this); adapter.notifyDataSetChanged(); } /** tell adapter that cursor is no longer valid*/ @Override public void onLoaderReset(Loader<Cursor> arg0) { Log.i(TAG,"---- onLoaderReset -----"); adapter.swapCursor(null); } @Override public void onAttach(Activity activity) { super.onAttach(activity); parentActivity = (ListParent) activity; parentActivity.setList(this); } 
+4
source share
2 answers

I had the same problem, and I solved it by carefully reading the documentation.

According to the docs http://developer.android.com/reference/android/widget/CursorAdapter.html#swapCursor(android.database.Cursor)

The swapCursor(Cursor data) method returns the original open cursor. If the new cursor is the same as the old, or if it was not old, it returns null.

By changing my code from

 @Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { adapter.swapCursor(data); } 

to

 @Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { Cursor cursor = adapter.swapCursor(data); if (cursor != null) { cursor.close(); } } 

I stopped these warnings.

Note. You must do the same for the onLoaderReset() method. Even if you execute adapter.swapCursor(null) , it returns the old cursor.

0
source

You should use changeCursor(Cursor cursor) instead of swapCursor(Cursor cursor)

If you look at the documentation , you will see that it also closes the old cursor.

0
source

Source: https://habr.com/ru/post/1490133/


All Articles