Skip to content

Instantly share code, notes, and snippets.

@czyrux
Last active August 29, 2015 14:15
Show Gist options
  • Save czyrux/8d36a70bb1babbde8540 to your computer and use it in GitHub Desktop.
Save czyrux/8d36a70bb1babbde8540 to your computer and use it in GitHub Desktop.
Utility Loader class implementation which extends AsyncTaskLoader and handles caveats regarding loader lifecycle. It also provides error handling and a helper class to decouple the loader job task.
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
/**
* Loader which extends AsyncTaskLoader and handles caveats as pointed out in
* http://code.google.com/p/android/issues/detail?id=14944.
* <p/>
*
* @param <T> data type
* @author Antonio Gutierrez <[email protected]>
*/
public class AsyncLoader<T> extends AsyncTaskLoader<LoaderResult<T>> {
private LoaderResult<T> result;
private final LoaderTask<T> task;
private volatile boolean loading;
public AsyncLoader(Context ctx, LoaderTask<T> task) {
super(ctx);
if (task == null) {
throw new IllegalArgumentException("LoaderTask cannot be null");
}
this.task = task;
}
@Override
protected void onStartLoading() {
if (result != null) {
// Deliver any previously loaded data immediately.
deliverResult(result);
}
// If there is not current data, start the job.
forceLoad();
}
@Override
public LoaderResult<T> loadInBackground() {
loading = true;
LoaderResult<T> data;
try {
T content = task.getData();
data = new LoaderResult<>(content);
} catch (Exception e) {
data = new LoaderResult<>(e);
}
return data;
}
@Override
protected void onStopLoading() {
// The Loader is in a stopped state, so we should attempt to cancel the
// current load (if there is one).
cancelLoad();
}
@Override
public void deliverResult(LoaderResult<T> dataLoaded) {
loading = false;
if (isReset()) {
// The Loader has been reset; ignore the result and invalidate the data.
result = null;
return;
}
this.result = dataLoaded;
if (isStarted()) {
// If the Loader is in a started state, deliver the results to the
// client. The superclass method does this for us.
super.deliverResult(result);
}
}
@Override
protected void onReset() {
// Ensure the loader has been stopped.
onStopLoading();
// Release resources.
result = null;
}
public boolean isLoading() {
return loading;
}
public boolean hasMoreData() {
return task.hasMoreData();
}
public void load() {
// It will force load unless there is nothing already loading
if (!isLoading()) {
super.forceLoad();
}
}
}
/**
* Result obtained from an AsyncLoader task.
* @param <T> data type
* @author Antonio Gutierrez <[email protected]>
*/
public class LoaderResult<T> {
private final T data;
private final Exception errorException;
public LoaderResult(T data) {
this.data = data;
this.errorException = null;
}
public LoaderResult(Exception errorException) {
this.errorException = errorException;
this.data = null;
}
public boolean isOk() {
return data != null;
}
public T getData() {
return data;
}
public Exception getErrorException() {
return errorException;
}
}
/**
* Carry out the task of loading the data for AsyncLoader.
* It can perform IO or network task.
* @param <T> data type
* @author Antonio Gutierrez <[email protected]>
*/
public interface LoaderTask<T> {
public T getData();
boolean hasMoreData();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment