6

我認爲使用CursorLoaders和Loadermanagers的好處之一是您不需要手動管理遊標的生命週期。所以我使用loader管理器將適配器綁定到使用支持包的AutoCompleteTextView。IllegalStateException - 使用AutocompleteTextView支持LoaderManager

它工作得很好,只是它隨機拋出一個錯誤,說「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) 

什麼可能是錯的任何想法?

+1

儘管我還沒有解決方案,但我只是擴展了AutoCompleteTextView,在圍繞「super」語句的try/catch循環中的onFilterComplete中發現錯誤,忽略它並繼續前進。我不知道爲什麼會發生或如何處理它。問題解決了。儘管如此。希望能有更優雅的解決方案。 – 2012-08-17 04:04:50

+0

我正在做類似的事情! http://stackoverflow.com/questions/12854336/autocompletetextview-backed-by-cursorloader – toobsco42 2012-10-12 07:36:50

+0

@BhagwadJalPark我已經解決了這個問題,因爲你有。 Tony提出的解決方案(檢查OnLoadFinished中的關閉狀態)對我無效。以下是我根據自己的洞察力編寫的包裝類:https://gist.github.com/esilverberg/5606551 – esilver 2013-05-19 03:29:45

回答

7

OnLoadFinished似乎有時會被一個死光標調用 - 如果你在光標上放一個isClosed()的測試,那麼你會發現它在一次(大數)嘗試中被關閉。

不幸的是,「標準」的代碼放在OnLoadFinished馬上就在適配器上changeCursor()的,那麼,接踵而來的是一片混亂,stackdumps,瘟疫等

我的解決方案並不比漂亮你的try/catch ..忽略僞造的OnLoadFinished,並冒着最終用戶得到一個空白的UI的風險。

+1

感謝您的寶貴意見。對於這個特殊情況,我已經完全拋棄了loadermanager/cursorloaer,並實現了另一種使用setfilterqueryprovider的方法。但是你的解決方案似乎是最好的選擇。也許我們可以在某處提交錯誤報告? – 2012-08-18 22:42:27