4

アクティビティのからを取得するによって入力されている一連のListViewオブジェクトがFragmentsにあります。私が理解しているように、すべてのデータベースとクローズアクションは、とによって完全に処理されるため、コードのどの時点でも、私は何も呼び出していません。CursorAdapterCursorLoaderManagerCursorLoaderManagerContentProvider.close()

ただし、次の例外が発生する場合があります。

02-19 11:07:12.308 E/AndroidRuntime(18777): java.lang.IllegalStateException: attempt to re-open an already-closed object: android.database.sqlite.SQLiteQuery (mSql = SELECT * FROM privileges WHERE uuid!=?) 
02-19 11:07:12.308 E/AndroidRuntime(18777): at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:33)
02-19 11:07:12.308 E/AndroidRuntime(18777): at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:82)
02-19 11:07:12.308 E/AndroidRuntime(18777): at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:164)
02-19 11:07:12.308 E/AndroidRuntime(18777): at android.database.sqlite.SQLiteCursor.onMove(SQLiteCursor.java:147)
02-19 11:07:12.308 E/AndroidRuntime(18777): at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:178)
02-19 11:07:12.308 E/AndroidRuntime(18777): at android.database.CursorWrapper.moveToPosition(CursorWrapper.java:162)
02-19 11:07:12.308 E/AndroidRuntime(18777): at android.widget.CursorAdapter.getView(CursorAdapter.java:241)

CursorAdapterいつ呼び出されるかgetView(...)getItem(...)またはgetItemId(...)呼び出されているかを示すログコードを自分に挿入しました。これは、別のアダプターgetView(...)で多くの秒が発生した後、特定のアダプターで最初に発生しているように見えます。getView(...)また、ユーザーがアプリ内を何度も移動した後にも発生します。

Cursorこれにより、アダプタのforがに保持されているのに、またはCursorAdapterによって誤って閉じられているのではないかと思います。これは可能ですか?アプリ/アクティビティ/フラグメントのライフサイクルイベントに基づいてハウスキーピングを行う必要がありますか?ContentProviderLoaderCursorAdapter

ContentProviderクエリメソッド:

class MyContentProvider extends ContentProvider {
//...

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
        Cursor query = db.query(getTableName(uri), projection, selection, selectionArgs, null, null, sortOrder);
        query.setNotificationUri(getContext().getContentResolver(), uri);
        return query;
    }

//...
}

典型的なLoaderCallbacks

LoaderCallbacks<Cursor> mCallbacks = new LoaderCallbacks<Cursor>() {

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        mArticleAdapter.swapCursor(null);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        if(cursor.isClosed()) {
            Log.d(TAG, "CURSOR RETURNED CLOSED");
            Activity activity = getActivity();
            if(activity!=null) {
                activity.getLoaderManager().restartLoader(mFragmentId, null, mCallbacks);
            }
            return;
        }
        mArticleAdapter.swapCursor(cursor);
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        triggerArticleFeed();
        CursorLoader cursorLoader = null;

        if(id == mFragmentId) {
            cursorLoader = new CursorLoader(getActivity(),
                                            MyContentProvider.ARTICLES_URI,
                                            null,
                                            ArticlesContentHelper.ARTICLES_WHERE,
                                            ArticlesContentHelper.ARTICLES_WHEREARGS,
                                            null);
        }
        return(cursorLoader);
    }
};

CursorAdapterコンストラクタ:

public ArticlesCursorAdapter(Context context, Cursor c) {
    super(context, c, 0);
    mImageloader = new ImageLoader(context);
}

私はこの質問を読みましたが、残念ながら、私が使用していることを示唆しているだけなので、私の問題に対する答えは得られていませんContentProvider

IllegalStateException:すでに閉じられているオブジェクトを再度開こうとします。SimpleCursorAdapterの問題

明らかになったばかりの重要な新しい情報

プロジェクトの他の場所で、sを使用しておらず、 sを適切Loaderに管理していない他のコードを発見しました。Cursor上記と同じパターンを使用するようにこのコードを切り替えました。ただし、これで問題が解決した場合Cursorは、プロジェクトの一部で管理されていない場合、他の場所で適切に管理されているプロジェクトを強制終了する可能性があります。

くっつき回る。

新しい情報の結果

それはそれを修正しませんでした。

新しい考え

@Override
onDestroyView() {
    getActivity().getLoaderManager().destroyLoader(mFragmentId);
    //any other destroy-time code
    super.onDestroyView()
}

つまり、おそらくそうです、私は(またはライフサイクルイベントに沿って)ハウスキーピングを行う必要があります。CursorAdapterCursorLoader

新しいアイデアの成果

いいえ。

前のアイデア

ちょっとした調整を加えると、動作することがわかりました。ただし、非常に複雑なので、おそらく質問全体を書き直す必要があります。

4

2 に答える 2

0

カーソルの代わりにnullをアダプターコンストラクターにパスしようとすることができます。次に、アダプタで SwapCursor(Cursor c) をオーバーライドし、そこにカーソル データの初期化を移動し、データ ローダーの OnLoadFinished(Loader loader, Cursor data) メソッドで呼び出します。

enter code here
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
    // ... building your query here
       mSimpleCursorAdapter = new mSimpleCursorAdapter(getActivity().getApplicationContext(),
           layout, null, from, to, flags);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
       contentAdapter.swapCursor(data);
    }
于 2015-07-29T12:17:37.630 に答える
0

データセットを更新しましたか? コンテンツ リゾルバの変更を通知するために、カーソルが再ロードされた可能性があります。

getContentResolver().notifyChange(URI, null);

通知 URI を設定している場合、これにより現在のカーソルが閉じられ、カーソル ローダーによって新しいカーソルが返されます。onLoadCompleteListener を登録している場合は、新しいカーソルを取得できます。

mCursorLoader.registerListener(0, new OnLoadCompleteListener<Cursor>() {
    @Override
    public void onLoadComplete(Loader<Cursor> loader, Cursor cursor) {
        // Set your listview's CursorAdapter
    }
});
于 2013-02-19T11:45:48.567 に答える