1

After I let my user download files to cloud, I want my app to restart its loader.

Previously, onLoadFinished is not always being called (randomly), when I wrote my code in the following way

public void reloadAfterOpenFromCloud() {
    LoaderManager loaderManager = this.getLoaderManager();
    loaderManager.restartLoader(0, bundle, this);
}

After referring to the discussion in Android - onLoadFinished not called, I modify my code to

public void reloadAfterOpenFromCloud() {
    // https://stackoverflow.com/questions/16014992/android-onloadfinished-not-called
    // This seems to be a realiable way, to make sure onCreateLoader and onLoadFinished will
    // be called.
    LoaderManager loaderManager = this.getLoaderManager();
    Loader loader = loaderManager.getLoader(0);
    if (loader != null) {
        loaderManager.destroyLoader(0);
    }
    loaderManager.restartLoader(0, bundle, this);
}

This reduces the chance of not calling onLoadFinished. However still, it will randomly happen, if I

  1. Do a clear cache, clean uninstall on my app.
  2. Install the app.
  3. Run reloadAfterOpenFromCloud. Again, randomly, onLoadFinished will not be called.

When onLoadFinished is not being called, if I run reloadAfterOpenFromCloud again, onLoadFinished will be called.

I'm using latest com.android.support:support-v4:25.0.0 and targetSdkVersion 25.

I was wondering, is there any realiable workaround, to ensure onLoadFinished is always being called, when loader restarted?


The following are part of my code snippets.

public void reloadAfterOpenFromCloud() {
    // https://stackoverflow.com/questions/16014992/android-onloadfinished-not-called
    // This seems to be a realiable way, to make sure onCreateLoader and onLoadFinished will
    // be called.
    LoaderManager loaderManager = this.getLoaderManager();
    Loader loader = loaderManager.getLoader(0);
    if (loader != null) {
        loaderManager.destroyLoader(0);
    }
    loaderManager.restartLoader(0, bundle, this);
}

static class HomeMenuRowInfosLoader extends AsyncTaskLoader<List<HomeMenuRowInfo>> {

    private List<HomeMenuRowInfo> homeMenuRowInfos = null;

    public HomeMenuRowInfosLoader(Context context) {
        super(context);
    }

    @Override
    public List<HomeMenuRowInfo> loadInBackground() {
        ...
        return homeMenuRowInfos;
    }

    /**
     * Handles a request to cancel a load.
     */
    @Override 
    public void onCanceled(List<HomeMenuRowInfo> homeMenuRowInfos) {
        super.onCanceled(homeMenuRowInfos);
    }

    /**
     * Handles a request to stop the Loader.
     * Automatically called by LoaderManager via stopLoading.
     */
    @Override 
    protected void onStopLoading() {
        // Attempt to cancel the current load task if possible.
        cancelLoad();
    }

    /**
     * Handles a request to start the Loader.
     * Automatically called by LoaderManager via startLoading.
     */
    @Override        
    protected void onStartLoading() {
        if (this.homeMenuRowInfos != null) {
            deliverResult(this.homeMenuRowInfos);
        }

        if (takeContentChanged() || this.homeMenuRowInfos == null) {
            forceLoad();
        }
    }

    /**
     * Handles a request to completely reset the Loader.
     * Automatically called by LoaderManager via reset.
     */
    @Override 
    protected void onReset() {
        super.onReset();

        // Ensure the loader is stopped
        onStopLoading();

        // At this point we can release the resources associated with 'apps'
        // if needed.
        this.homeMenuRowInfos = null;
    }        
}

@Override
public Loader<List<HomeMenuRowInfo>> onCreateLoader(int arg0, Bundle bundle) {
    return new HomeMenuRowInfosLoader(this.getActivity());
}

// Not being called always when restart loader
@Override
public void onLoadFinished(Loader<List<HomeMenuRowInfo>> arg0, List<HomeMenuRowInfo> homeMenuRowInfos) {
    ...
Community
  • 1
  • 1
Cheok Yan Cheng
  • 47,586
  • 132
  • 466
  • 875

1 Answers1

0

You need to implement some sort of observer in your HomeMenuRowInfosLoader that will call onContentChanged() when the user has finished the cloud file transfer.

If onContentChanged() is never called, takeContentChanged() will always return false and forceLoad() will not be called within onStartLoading() after the first load at which point homeMenuRowInfos is not equal to null.

kris larson
  • 30,387
  • 5
  • 62
  • 74
  • I had debug. `forceLoad` is called, when the "onLoadFinished is not called" problem occurs. – Cheok Yan Cheng Nov 09 '16 at 17:24
  • If you have a matching `forceLoad` for every `restartLoader` but aren't getting `onLoadFinished`, I'm not sure what that is. In `loadInBackground`, do you always do `homeMenuRowInfos = new ArrayList<>()` or do you reuse the list? I see some code in `LoaderManager` that looks like it will skip `onLoadFinished` if the new data == previous data. – kris larson Nov 09 '16 at 18:52