سؤال

The android documentation for Loader#stopLoading() says:

When using a Loader with LoaderManager, you must not call this method yourself, or you will conflict with its management of the Loader.

But is that really true? Specifically I am interested in CursorLoader. I looked the through the Android source for version 4.2 and it seems pretty benign. Has anyone tried using this method and seen a problem? Is there an alternative if I want to keep the current active Cursor last delivered by the CursorLoader and also stop it temporarily from reloading due to the internal ContentObserver being triggered? Basically I want to make a bunch of changes to the ContentProvider that is the source of this managed Cursor and I don't want the Loader kicking off a ton of loads until I am done.

هل كانت مفيدة؟

المحلول

I agree with a.ch that relying on the Android source code isn't the way to go not just because you risk breaking your app with future updates but also because of the hundreds of modified versions of Android (the joy of fragmentation). stopLoading() wouldn't work anyway, for reasons see below.

cancelLoad() will not close the underlying cursor (where did you get that from?) so while this method will cancel a load if one is in progress, it won't prevent future loads. And even if it would prevent future loads it wouldn't work either (for the same reasons stopLoading() won't work).

My initial idea to solve this was to implement a custom CursorLoader and just override the onContentChanged() method using a flag to decide whether to "take" the changes or not. This way one could temporarily disable the update:

class MyCursorLoader extends CursorLoader {
    private boolean mDontUpdate;

    public MyCursorLoader(Context context, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        super(context, uri, projection, selection, selectionArgs, sortOrder);
    }

    @Override
    public void onContentChanged () {
        if (! mDontUpdate) {
            super.onContentChanged();
        }
    }

    @Override
    public boolean takeContentChanged () {
        return mDontUpdate ? false : super.takeContentChanged();
    }

    void dontUpdate(boolean dontUpdate) {
        mDontUpdate = dontUpdate;
    }
}

You would use this class instead of the CursorLoader in the onCreateLoader(int, Bundle) and you would set the don't update flag during the database update.

Now that works nicely except it doesn't. While it's not clear from the question what the CursorLoader and the resulting Cursor are used for I assume the Cursor is used in a CursorAdapter for a ListView or a similar widget. The widget registers its own ContentObserver to the Cursor and updates the views accordingly. So even if no new Cursor is loaded a ListView (a GridView or any other widget attached to the Cursor) would still update (Android would call the newView, bindView methods in a CursorAdapter).

This brings me to my next approach. Although it's not clear from your question I assume you are doing some modifications to a database? If that's the case then why not do all the modifications in a single transaction? If done in one transaction changes wouldn't show anywhere before the transaction is committed and that's probably what you want.

If your Cursor isn't backed by a database though you would probably have to remove the Adapter from your widget during the update.

نصائح أخرى

First of all, you shouldn't rely on the android source code: if there are no any issues with the current android build, it doesn't mean there won't be any in future. I'd suggest considering android system as a black box, this will let you write robust and reliable apps.

According to your question on the alternative, consider cancelLoad().

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top