Android - attempt to re-open an already-closed object: SQLiteQuery using loaderManager

ⅰ亾dé卋堺 提交于 2019-12-10 22:27:38

问题


I am fairly new to android and I have some problems with a filtered listView and The activity it's in changing from landscape mode to portrait mode or or vice versa. I have an editText that I use for filtering "drinkSearch", this filtering works as long as I do not change the viewing angle (portrait vs landscape). This is the error that I get:

java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteQuery: SELECT _id, name FROM drinks

As you can see in the following code I use the interface LoaderManager.LoaderCallbacks, this concept is kinda new for me and I am not sure where things go wrong. I would appreciate all help, thanks in advance!

public class Drinks_Fragment extends Fragment implements LoaderManager.LoaderCallbacks {

private static final int DRINKS_LIST_LOADER = 0x01;
private SimpleCursorAdapter adapter;
private ListView drinksList;
private String LOG;
private EditText drinkSearch;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.drinks_list, container, false);
    drinkSearch = (EditText)view.findViewById(R.id.drinkInputSearch);
    drinksList = (ListView) view.findViewById(R.id.drinksList);
    drinksList.setEmptyView(view.findViewById(R.id.empty_list_view));

    String[] from = {DrinksTable.COLUMN_NAME};
    int[] to = {R.id.drinkName};
    getLoaderManager().initLoader(DRINKS_LIST_LOADER, null, this);
    adapter = new SimpleCursorAdapter(getActivity().getApplicationContext(), R.layout.drinks_list_item,null, from, to, 0);
    drinksList.setAdapter(adapter);

In this part I ask my contentProvider for a new Cursor based on the string entered in the searchDrink editText. (Following code, until "return view" is just below the part above, same onCreateView method)

    drinkSearch.addTextChangedListener(new TextWatcher() {

        @Override
        public void onTextChanged(CharSequence s, int arg1, int arg2, int arg3) {
            // When user changed the Text
            adapter.getFilter().filter(s.toString());
        }

        @Override
        public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
            // TODO Auto-generated method stub

        }

        @Override
        public void afterTextChanged(Editable arg0) {
            // TODO Auto-generated method stub
        }
    });

    adapter.setFilterQueryProvider(new FilterQueryProvider() {

        public Cursor runQuery(CharSequence constraint) {
            String value = "%"+constraint.toString()+"%";
            ContentResolver content = getActivity().getContentResolver();
            return content.query(CupProvider.DRINKS_URI,new String[]{DrinksTable.COLUMN_ID,DrinksTable.COLUMN_NAME},DrinksTable.COLUMN_NAME + " LIKE ?",new String[]{value},null);
        }
    });

    return view;
}

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu,v,menuInfo);
    MenuInflater inflater = getActivity().getMenuInflater();
    inflater.inflate(R.menu.drink_actions,menu);
}


@Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
    String[] projection = {DrinksTable.COLUMN_ID, DrinksTable.COLUMN_NAME};
    CursorLoader cursorLoader = new CursorLoader(getActivity(), CupProvider.DRINKS_URI, projection, null, null, null);
    return cursorLoader;
}

@Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
    adapter.swapCursor(cursor);

}

@Override
public void onLoaderReset(Loader<Cursor> cursorLoader) {
    // data is not available anymore, delete reference
    adapter.swapCursor(null);
}

}

Here are 2 pictures to show how it looks at the moment: http://oi42.tinypic.com/dfc702.jpg http://oi43.tinypic.com/2ylqkqa.jpg


回答1:


Your code is a bit hard to make sense of due to poor formatting.

Anyway, the supplied answer is actually not a fix. The cursor returned at onLoadFinished should be guaranteed not to be closed, so you're loading your cursor in the wrong manner. Specifically, when you call

adapter.getFilter().filter(s.toString());

I don't really understand what goes on here, but I do understand that you should do something else. Just store the query filter in a field within your Fragment and run getLoaderManager().restartLoader(DRINKS_LIST_LOADER, null, this);. Note that you run restartLoader, and not initLoader, because you have different data that you want to query for.

In your onCreateLoader, you should use the filter that you stored as an instance variable for the selection.

Some background

initLoader loads the data that was loaded in the last run, if it had run before. This is why you call in in the initialization method of your Fragment/Activity. This is handy because you won't have to requery on orientation change.

restartLoader cleans up previously loaded data so that you get a new Loader to work with (likely) different data.


If you aren't really sure what you're doing still, make sure to read this article, which is a very good introductory article on Loaders with sample code that looks very much like what you want to achieve. Loaders are pretty enigmatic at first, but once you get the hang of it it's smooth sailing.




回答2:


Fixed it:

@Override public void onLoadFinished(Loader cursorLoader, Cursor cursor) { if(!cursor.isClosed()){ adapter.swapCursor(cursor); } }

I do have another problem now, my list does not get updated automatically...




回答3:


Adding this line in AndroidManifest helped me in the same situation:

android:configChanges="keyboardHidden|orientation|screenSize"



回答4:


This is because after filtering, the original cursor is closed because changeCursor is called. Overriding changeCursor with:

super.swapCursor(cursor)

in your SimpleCursorAdapter makes sure the original cursor is managed by the CursorLoader.



来源:https://stackoverflow.com/questions/17458251/android-attempt-to-re-open-an-already-closed-object-sqlitequery-using-loaderm

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!