Is it necessary to implement both LoaderCallbacks and OnLoadCompleteListener to get notifications of changes in a ContentProvider?

人走茶凉 提交于 2019-12-12 03:45:41

问题


I have an application which is using Loaders to get at a database which is also being edited by an IntentService. I receive data from the Loader through a LoaderCallbacks implementation, which is working fine.

I am also using ContentResolver#notifyChange(Uri, ContentObserver) to trigger reload. However, this only works when I call Cursor#setNotificationUri(Uri) beforehand.

I can find no reference to the latter method in any documentation and it seems in fact this may be causing crashes: see also

IllegalStateException "attempt to re-open an already-closed object" in SimpleCursorAdapter from ContentProvider

However, without this call on the Cursor the LoaderCallbacks#onLoadFinished(Loader<Cursor>, Cursor) is only hit after the initial load, and not after the notification. Do I also need to implement an OnLoadCompleteListener to do, well, exactly the same thing?

ContentProvider query method:

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

//...
}

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

回答1:


Implementing both listeners is a very bad idea:

02-19 17:46:25.139: E/AndroidRuntime(24886): FATAL EXCEPTION: main
02-19 17:46:25.139: E/AndroidRuntime(24886): java.lang.IllegalStateException: There is already a listener registered
02-19 17:46:25.139: E/AndroidRuntime(24886):    at android.content.Loader.registerListener(Loader.java:152)
02-19 17:46:25.139: E/AndroidRuntime(24886):    at android.app.LoaderManagerImpl$LoaderInfo.start(LoaderManager.java:273)
02-19 17:46:25.139: E/AndroidRuntime(24886):    at android.app.LoaderManagerImpl.installLoader(LoaderManager.java:523)
02-19 17:46:25.139: E/AndroidRuntime(24886):    at android.app.LoaderManagerImpl.createAndInstallLoader(LoaderManager.java:510)
02-19 17:46:25.139: E/AndroidRuntime(24886):    at android.app.LoaderManagerImpl.initLoader(LoaderManager.java:563)

So in fact the answer to this question is:

It is necessary NOT to implement both listeners.



来源:https://stackoverflow.com/questions/14963524/is-it-necessary-to-implement-both-loadercallbacks-and-onloadcompletelistener-to

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