IllegalStateException - 使用 AutocompleteTextView 支持 LoaderManager

Posted

技术标签:

【中文标题】IllegalStateException - 使用 AutocompleteTextView 支持 LoaderManager【英文标题】:IllegalStateException - Support LoaderManager with AutocompleteTextView 【发布时间】:2012-08-13 12:10:08 【问题描述】:

我认为使用 CursorLoaders 和 Loadermanagers 的好处之一是您无需手动管理光标的生命周期。所以我使用 loadermanager 将适配器绑定到使用支持包的 AutoCompleteTextView。

它工作得很好,除了它随机抛出一个错误说“IllegalStateException - 尝试重新打开一个已经关闭的对象”。如果我们使用加载器管理器,这肯定不应该发生吗?

代码如下:

package com.bhagwad.tennis;

import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.SimpleCursorAdapter;
import android.support.v4.widget.SimpleCursorAdapter.CursorToStringConverter;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AutoCompleteTextView;
import android.widget.Button;

import com.bhagwad.tennis.TennisSchedule.TennisScheduleColumns;


public class WidgetConfiguration extends FragmentActivity implements OnClickListener, LoaderCallbacks<Cursor> 

    Button mSaveWidget;
    AutoCompleteTextView mPlayerName;
    int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
    String mSelection ="";
    SimpleCursorAdapter mAdapter;

    public static String PREFS = "com.bhagwad.tennis.appwidget";
    public static final String PREFS_PREFIX_KEY = "prefix_";

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.widget_configuration);

        mPlayerName = (AutoCompleteTextView) findViewById(R.id.edit_filter);

        mPlayerName.addTextChangedListener(new TextWatcher() 

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) 

                if (!s.equals(""))
                    mSelection = s.toString();
                else
                    mSelection = "";

                getSupportLoaderManager().restartLoader(0, null, WidgetConfiguration.this);



            

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count,
                    int after) 
                // TODO Auto-generated method stub

            

            @Override
            public void afterTextChanged(Editable s) 
                // TODO Auto-generated method stub

            
        );

        // Set up the adapter

        mAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, null, new String[] TennisScheduleColumns.PLAYER_NAME, new int[] android.R.id.text1, 0);
        mAdapter.setCursorToStringConverter(new CursorToStringConverter() 

            @Override
            public CharSequence convertToString(Cursor c) 

                return c.getString(c.getColumnIndexOrThrow(TennisScheduleColumns.PLAYER_NAME)); 

            
        );

        mPlayerName.setAdapter(mAdapter);

        getSupportLoaderManager().initLoader(0, null, this);

    


    @Override
    public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) 

        return new CursorLoader(this, TennisScheduleColumns.CONTENT_URI_PLAYERS, new String[] TennisScheduleColumns._ID, TennisScheduleColumns.PLAYER_NAME, TennisScheduleColumns.PLAYER_NAME + " LIKE ?", new String[] "%"+mSelection+"%", null);

    


    @Override
    public void onLoaderReset(Loader<Cursor> arg0) 
        mAdapter.swapCursor(null);

    

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


    



这是错误堆栈:

08-16 22:21:23.244: E/AndroidRuntime(25475): java.lang.IllegalStateException: attempt to re-open an already-closed object: android.database.sqlite.SQLiteQuery (mSql = SELECT _id, player_name FROM players WHERE (player_name LIKE ?)) 
08-16 22:21:23.244: E/AndroidRuntime(25475):    at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:33)
08-16 22:21:23.244: E/AndroidRuntime(25475):    at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:82)
08-16 22:21:23.244: E/AndroidRuntime(25475):    at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:164)
08-16 22:21:23.244: E/AndroidRuntime(25475):    at android.database.sqlite.SQLiteCursor.onMove(SQLiteCursor.java:147)
08-16 22:21:23.244: E/AndroidRuntime(25475):    at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:178)
08-16 22:21:23.244: E/AndroidRuntime(25475):    at android.database.CursorWrapper.moveToPosition(CursorWrapper.java:162)
08-16 22:21:23.244: E/AndroidRuntime(25475):    at android.support.v4.widget.CursorAdapter.getItem(CursorAdapter.java:213)
08-16 22:21:23.244: E/AndroidRuntime(25475):    at android.widget.AutoCompleteTextView.buildImeCompletions(AutoCompleteTextView.java:1113)
08-16 22:21:23.244: E/AndroidRuntime(25475):    at android.widget.AutoCompleteTextView.showDropDown(AutoCompleteTextView.java:1072)
08-16 22:21:23.244: E/AndroidRuntime(25475):    at android.widget.AutoCompleteTextView.updateDropDownForFilter(AutoCompleteTextView.java:950)
08-16 22:21:23.244: E/AndroidRuntime(25475):    at android.widget.AutoCompleteTextView.onFilterComplete(AutoCompleteTextView.java:932)
08-16 22:21:23.244: E/AndroidRuntime(25475):    at android.widget.Filter$ResultsHandler.handleMessage(Filter.java:285)
08-16 22:21:23.244: E/AndroidRuntime(25475):    at android.os.Handler.dispatchMessage(Handler.java:99)
08-16 22:21:23.244: E/AndroidRuntime(25475):    at android.os.Looper.loop(Looper.java:137)
08-16 22:21:23.244: E/AndroidRuntime(25475):    at android.app.ActivityThread.main(ActivityThread.java:4507)

对可能出现的问题有任何想法吗?

【问题讨论】:

虽然我仍然没有解决方案,但我只是扩展了 AutoCompleteTextView,在围绕“super”语句的 try/catch 循环中捕获了 onFilterComplete 中的错误,忽略它并继续前进。我不知道它为什么会发生或如何处理它。问题解决了。虽然很乱。希望有更优雅的解决方案。 我在这里做类似的事情!! ***.com/questions/12854336/… @BhagwadJalPark 我已经解决了这个问题。 Tony 提出的解决方案(检查 OnLoadFinished 中的关闭状态)对我不起作用。这是我根据您的见解编写的包装类:gist.github.com/esilverberg/5606551 【参考方案1】:

OnLoadFinished 似乎有时会被一个死游标调用 - 如果你在你通过的游标上对 isClosed() 进行测试,你会发现它在一次(大量)尝试中关闭。

不幸的是,放在 OnLoadFinished 中的“标准”代码会立即在适配器上执行 changeCursor(),然后接下来是混乱、堆栈转储、瘟疫等。

我的解决方案并不比你的 try/catch 更漂亮。忽略虚假的 OnLoadFinished 并冒最终用户获得空白 UI 的风险。

【讨论】:

谢谢你的花絮。对于这种特殊情况,我完全抛弃了 loadermanager/cursorloaer,并使用 setfilterqueryprovider 实现了另一种方法来执行此操作。但是您的解决方案似乎是最好的方法。也许我们可以在某处提交错误报告?

以上是关于IllegalStateException - 使用 AutocompleteTextView 支持 LoaderManager的主要内容,如果未能解决你的问题,请参考以下文章

IllegalStateException:无法订阅。处理器已终止

Java.lang.IllegalStateException:已附加

转:java.lang.IllegalStateException异常产生的原因及解决办法

java.lang.IllegalStateException:片段未附加到活动

EJB java.lang.IllegalStateException

错误:java.lang.IllegalStateException:没有包含点