Search code examples
javaandroidasynctaskloader

AsyncTaskLoader does not cache data offline


I have created an AsyncTaskLoader for loading JSON data from an API. However, I noticed that if I rotate the screen of my device, it tries to load the data from the API again.

As a result, if I turn off my Internet connection and rotate the screen, the loader fails to return data since the HTTP request fails.

// NewsLoader.java
public class NewsLoader extends AsyncTaskLoader<String> {
    private String url;

    public NewsLoader(@NonNull Context context, String url) {
        super(context);
        this.url = url.trim();
    }

    @Override
    protected void onStartLoading() {
        forceLoad();
    }

    @Override
    public String loadInBackground() {
        if (url == null || url.isEmpty()) return null;
        return NetworkUtils.fetchNews(url);
    }
}

Then,

// NewsActivity.java

// Initialising the loader
LoaderManager.getInstance(this).initLoader(LOADER_ID, args, this);

// onCreateLoader method
public Loader<String> onCreateLoader(int id, @Nullable Bundle args) {
    // Process args and get url
    return new NewsLoader(this, url);
}

As far as I know, this isn't normal behaviour for a loader. Any idea what is wrong?


Solution

  • I eventually figured out what the problem was. The data has to be cached manually, intercepting the loaded data within deliverResult() and saving it in an instance variable for later use.

    Here is the updated code.

    // NewsLoader.java
    public class NewsLoader extends AsyncTaskLoader<String> {
        private String url;
        private String cachedData = null;
    
        public NewsLoader(@NonNull Context context, String url) {
            super(context);
            this.url = url.trim();
        }
    
        @Override
        protected void onStartLoading() {
            if (cachedData != null) deliverResult(cachedData);
            else forceLoad();
        }
    
        @Override
        public String loadInBackground() {
            if (url == null || url.isEmpty()) return null;
            return NetworkUtils.fetchNews(url);
        }
    
        @Override
        public void deliverResult(String data) {
            cachedData = data;
            super.deliverResult(data);
        }
    }