androidloaderasynctaskloader

Android Loaders onLoadFinished() called immediately


I'm implementing network communication using loaders... because most of them recommend it and "they are lifecycle aware".

But in my case I've extended the AsyncTaskLoader overridden the loadInBackground() etc.etc. And at the end the onLoadFinished() is called normally.

But my problem occurs in case of a network error. If the data is null the onLoadFinished() is called immediately, without the network call.

As per the google docs:

In either case, the given callback is associated with the loader, and will be called as the loader state changes. If at the point of call the caller is in its started state, and the requested loader already exists and has generated its data, then callback onLoadFinished(Loader, D) will be called immediately (inside of this function), so you must be prepared for this to happen.

So is this something I've to handle, keep a track using flag and next time call restartLoader() in my activity instead of initLoader(). Or I'm doing something wrong.

I'm posting important parts of my code below:

In Main Activity:

   protected void postJson(int loaderId, Parcelable object, boolean loadOffline) {
        Bundle bundle = new Bundle();
        bundle.putParcelable(Constants.OBJ, object);
        bundle.putBoolean(Constants.OFFLINE, loadOffline);
        loaderManager.initLoader(loaderId, bundle, this);
    }

NetworkAsyncTaskLoader

@Override
public Result loadInBackground() {
                Constants.verbose("loadInBackground Called");
                .....
                Response tempResult;
                try {
                    tempResult = loadFromNetwork();

                   ........
                } catch (IOException e) {
                    Constants.error("Network Error for loader Id: " + loaderId, e);
                    return null;
                }
        }



@Override
public void deliverResult(Result result) {
            Constants.verbose("deliverResult called");
            super.deliverResult(result);
        }

onLoadFinished() in Activity

    @Override
  public void onLoadFinished(Loader loader, NetworkAsyncTaskLoader.Result data) {
        hideProgress();
        Constants.debug("Load finished for: " + loader.getId());
        .....
    }

And below is the stack trace..

07-31 10:08:02.177 27677-28061/com.sample.test D/OkHttp: <-- HTTP FAILED: java.net.ConnectException: Failed to connect to ...
07-31 10:08:02.179 27677-28061/com.sample.test E/Test: Network Error for loader Id: 101
                                                                  java.net.ConnectException: Failed to connect to ...
07-31 10:08:02.192 27677-27677/com.sample.test V/Test: deliverResult called
07-31 10:08:02.193 27677-27677/com.sample.test D/Test: Load finished for: 101
07-31 10:08:08.982 27677-27677/com.sample.test D/Test: Load finished for: 101

As you can see next time I call initLoader() or try to initiate network call.. It directly calls onLoadFinished()

Update:

Well I ended up by creating a flag which sets to false if there is network error or something goes wrong and then if flag is true call restartLoader() instead.


Solution

  • Once you call deliverResult() the data is "pushed out" to the onLoadFinished() callback method, This is as designed.

    If you call deliverResult(null) you're basically saying that your results are empty, from the LoaderManager point of view - your Loader finished his job, he "doesn't care" about the null value.

    TL;DR - Yes, You need to handle the null result yourself and call restartLoader() to make your Loader run again.