Android - 尝试重新打开一个已经关闭的对象 : SQLiteQuery using loaderManager

标签 android android-listview android-contentprovider android-sqlite android-loadermanager

我是 android 的新手,我在过滤 listView 和从横向模式更改为纵向模式或反之亦然的 Activity 中遇到了一些问题。我有一个用于过滤“drinkSearch”的 editText,只要我不改变视角(纵向与横向),此过滤就有效。这是我得到的错误:

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

正如您在下面的代码中看到的,我使用接口(interface) LoaderManager.LoaderCallbacks,这个概念对我来说有点新,我不确定 哪里出了问题。我将不胜感激所有帮助,在此先感谢!

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);

在这部分中,我根据在 searchDrink editText 中输入的字符串向我的 contentProvider 请求一个新的 Cursor。 (下面的代码,直到“return view”在上面部分的正下方,同样的onCreateView方法)

    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);
}

这里有 2 张图片展示了它现在的样子:http://oi42.tinypic.com/dfc702.jpg http://oi43.tinypic.com/2ylqkqa.jpg

最佳答案

由于格式不正确,您的代码有点难以理解。

无论如何,所提供的答案实际上并不能解决问题。在 onLoadFinished 处返回的游标应保证不会关闭,因此您以错误的方式加载了游标。具体来说,当你打电话时

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

我不太明白这里发生了什么,但我明白你应该做点别的事情。只需将查询过滤器存储在您的 Fragment 中的一个字段中,然后运行 ​​getLoaderManager().restartLoader(DRINKS_LIST_LOADER, null, this);。请注意,您运行的是 restartLoader,而不是 initLoader,因为您有不同的数据要查询。

在您的 onCreateLoader 中,您应该使用存储为 selection 实例变量的过滤器。

一些背景

initLoader 加载上次运行时加载的数据(如果之前运行过)。这就是您在 Fragment/Activity 的初始化方法中调用它的原因。这很方便,因为您不必重新查询方向更改。

restartLoader 清理以前加载的数据,以便您获得一个新的 Loader 来处理(可能)不同的数据。


如果您仍然不确定自己在做什么,请务必阅读 this article ,这是一篇关于 Loaders 的非常好的介绍性文章,带有示例代码,看起来非常像您想要实现的目标。装载机一开始非常神秘,但一旦掌握了它的窍门,它就会一帆风顺。

关于Android - 尝试重新打开一个已经关闭的对象 : SQLiteQuery using loaderManager,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17458251/

相关文章:

android - ListView Adapter - 何时收集附加到 View 的监听器?

android - 添加 fragment 作为 ListView header

android - ContentProvider 实现,如何将 "Selection"和 "SelectionArgs"转换为键值对?

android - 获取调用提供程序内部结构

android - android 上的 Apache cordova 滚动条在哪里?

Android WebView - 它支持摘要身份验证吗?

android - NoSuchMethodError : java. io.IOException.<init> 使用 Froyo 版本的 Google Play 服务时出现异常

java - 在 ListView android 的底部显示最新项目

android - 如何从 ListView 项更新 SQLite 行?

java - Android:一旦用户点击按钮,每 10 秒获取当前的前台 Activity