Skip to content

Instantly share code, notes, and snippets.

@HenokT
Last active February 27, 2018 03:17
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save HenokT/7873979 to your computer and use it in GitHub Desktop.
Save HenokT/7873979 to your computer and use it in GitHub Desktop.
An example of a Generic AsyncTaskLoader for Android
package com.yourcompany.util;
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
import android.util.Log;
import com.yourcompany.util.GenericAsyncTaskLoader.ServiceData;
/**
* A generic Loader that delegates its actual loading operation to a
* CustomLoaderCallbacks<T> instance passed through the constructor.
*/
public class GenericAsyncTaskLoader<T extends ServiceData> extends
AsyncTaskLoader<T> {
private static final String LOG_TAG = "GenericAsyncTaskLoader";
public static class ServiceData {
private Exception exception;
public ServiceData(Exception ex) {
this.exception = ex;
}
public boolean hasException() {
return exception != null;
}
}
public interface ExtendedLoaderCallbacks<T> {
public T onLoadInBackground();
public T onExceptionInBackground(Exception ex);
public void onLoadCanceled();
}
ExtendedLoaderCallbacks<T> mExtendeCallbacks;
T mData;
/**
* ServiceDataLoader expects a reference to an ExtendedLoaderCallbacks
* implementation for handling
* onLoadInBackground(),onExceptionInBackground() and onLoadCanceled()
* events
*
* @param context
* @param extendedCallbacks
*/
public ServiceDataLoader(Context context,
ExtendedLoaderCallbacks<T> extendedCallbacks) {
super(context);
mExtendeCallbacks = extendedCallbacks;
}
/**
* This is where the bulk of our work is done. This function is called in a
* background thread and should generate a new set of data to be published
* by the loader.
*/
@Override
public T loadInBackground() {
Log.d(LOG_TAG, "loadInBackground()");
// Retrieve data
T data = null;
try {
data = mExtendeCallbacks.onLoadInBackground();
} catch (Exception e) {
Log.e(LOG_TAG, "An error occurred wile loading data", e);
data = mExtendeCallbacks.onExceptionInBackground(e);
}
// Done!
return data;
}
/**
* Called when there is new data to deliver to the client. The super class
* will take care of delivering it; the implementation here just adds a
* little more logic.
*/
@Override
public void deliverResult(T data) {
Log.d(LOG_TAG, "deliverResult()");
if (isReset()) {
// An async query came in while the loader is stopped. We
// don't need the result.
if (data != null) {
onReleaseResources(data);
}
}
T oldData = data;
mData = data;
if (isStarted()) {
// If the Loader is currently started, we can immediately
// deliver its results.
super.deliverResult(data);
}
// At this point we can release the resources associated with
// 'oldData' if needed; now that the new result is delivered we
// know that it is no longer in use.
if (oldData != null) {
onReleaseResources(oldData);
}
}
/**
* Handles a request to start the Loader.
*/
@Override
protected void onStartLoading() {
Log.d(LOG_TAG, "onStartLoading()");
if (mData != null) {
// If we currently have a result available, deliver it
// immediately.
deliverResult(mData);
}
if (takeContentChanged() || mData == null) {
// If the data has changed since the last time it was loaded
// or is not currently available, start a load.
forceLoad();
}
}
/**
* Handles a request to stop the Loader.
*/
@Override
protected void onStopLoading() {
super.onStopLoading();
Log.d(LOG_TAG, "onStopLoading()");
// Attempt to cancel the current load task if possible.
cancelLoad();
}
/**
* Handles a request to cancel a load.
*/
@Override
public void onCanceled(T data) {
super.onCanceled(data);
Log.d(LOG_TAG, "onCanceled()");
mExtendeCallbacks.onLoadCanceled();
// At this point we can release the resources associated with 'apps'
// if needed.
onReleaseResources(data);
}
/**
* Handles a request to completely reset the Loader.
*/
@Override
protected void onReset() {
super.onReset();
Log.d(LOG_TAG, "onReset()");
// Ensure the loader is stopped
onStopLoading();
// At this point we can release the resources associated with 'apps'
// if needed.
if (mData != null) {
onReleaseResources(mData);
mData = null;
}
}
/**
* Helper function to take care of releasing resources associated with an
* actively loaded data set.
*/
protected void onReleaseResources(T data) {
// For a simple List<> there is nothing to do. For something
// like a Cursor, we would close it here.
}
}
/**
* An implementation of LoaderManager.LoaderCallbacks and
GenericAsyncTaskLoader.ExtendedCallbacks
*
*/
private class HomeScreenDataLoaderCallbacks implements
LoaderManager.LoaderCallbacks<HomeScreenData>,
ExtendedLoaderCallbacks<HomeScreenData> {
private Application mApplication = getApplication();
@Override
public Loader<HomeScreenData> onCreateLoader(int id, Bundle args) {
return new GenericAsyncTaskLoader<HomeScreenData>(mApplication, this);
}
@Override
public HomeScreenData onLoadInBackground() {
ServiceHelper helper = new ServiceHelper(mApplication);
return new HomeScreenData(helper.getHomeScreenStories(), helper.getWeatherCurrent(),
helper.getHomeScreenAds());
}
@Override
public HomeScreenData onExceptionInBackground(Exception ex) {
return new HomeScreenData(ex);
}
@Override
public void onLoadCanceled() {
dismissProgressDialog();
}
@Override
public void onLoadFinished(Loader<HomeScreenData> loader,
HomeScreenData data) {
if (data == null || data.hasException()) {
showDataLoadFailureDialog();
return;
}
mData = data;
if (isViewCreated()) {
updateViews();
}
dismissProgressDialog();
}
@Override
public void onLoaderReset(Loader<HomeScreenData> loader) {
dismissProgressDialog();
mData = null;
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (mData == null) {
showProgressDialog();
}
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(MAIN_DATA_LOADER_ID, null,
new DataLoaderCallbacks());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment