Created
March 22, 2013 16:14
-
-
Save jerrellmardis/5222580 to your computer and use it in GitHub Desktop.
Generic {@link AsyncTaskLoader} which also registers and handles data changes via a {@link BroadcastReceiver}.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.BroadcastReceiver; | |
import android.content.Context; | |
import android.content.Intent; | |
import android.content.IntentFilter; | |
import android.support.v4.content.AsyncTaskLoader; | |
/** | |
* Generic {@link AsyncTaskLoader} which also registers and handles data changes via a {@link BroadcastReceiver}. | |
* | |
* @author jmardis | |
*/ | |
public abstract class BaseAsyncTaskLoader<D> extends AsyncTaskLoader<D> { | |
protected DataObserverReceiver mDataObserverReceiver; | |
protected String mIntentFilterAction; | |
protected D mData; | |
public BaseAsyncTaskLoader(Context ctx) { | |
super(ctx); | |
} | |
public BaseAsyncTaskLoader(Context ctx, String intentFilterAction) { | |
this(ctx); | |
mIntentFilterAction = intentFilterAction; | |
} | |
@Override | |
public void deliverResult(D data) { | |
if (isReset()) { | |
// the Loader has been reset; ignore the result and invalidate the data. | |
onReleaseResources(data); | |
return; | |
} | |
// hold a reference to the old data so it doesn't get garbage collected. The old data may still be in use (i.e. bound to an adapter, etc.), so | |
// we must protect it until the new data has been delivered. | |
D oldData = mData; | |
mData = data; | |
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(data); | |
} | |
// invalidate the old data as we don't need it any more. | |
if (oldData != null && oldData != data) { | |
onReleaseResources(oldData); | |
} | |
} | |
@Override | |
protected void onStartLoading() { | |
if (mData != null) { | |
// deliver any previously loaded data immediately. | |
deliverResult(mData); | |
} | |
// begin monitoring the underlying data source. | |
if (mDataObserverReceiver == null && mIntentFilterAction != null && mIntentFilterAction.length() > 0) { | |
mDataObserverReceiver = new DataObserverReceiver(); | |
} | |
if (takeContentChanged() || mData == null) { | |
// When the observer detects a change, it should call onContentChanged() on the Loader, which will cause the next call to | |
// takeContentChanged() to return true. If this is ever the case (or if the current data is null), we force a new load. | |
forceLoad(); | |
} | |
} | |
@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(); | |
// note that we leave the observer as is; Loaders in a stopped state should still monitor the data source for changes so that the Loader | |
// will know to force a new load if it is ever started again. | |
} | |
@Override | |
protected void onReset() { | |
// ensure the loader has been stopped. | |
onStopLoading(); | |
// at this point we can release the resources associated with 'mData'. | |
if (mData != null) { | |
onReleaseResources(mData); | |
mData = null; | |
} | |
// the Loader is being reset, so we should stop monitoring for changes. | |
if (mDataObserverReceiver != null) { | |
getContext().unregisterReceiver(mDataObserverReceiver); | |
mDataObserverReceiver = null; | |
} | |
} | |
@Override | |
public void onCanceled(D data) { | |
// attempt to cancel the current asynchronous load. | |
super.onCanceled(data); | |
// the load has been canceled, so we should release the resources associated with 'data'. | |
onReleaseResources(data); | |
} | |
protected void onReleaseResources(D data) { | |
// for a simple List, there is nothing to do. For something like a Cursor, we would close it in this method. | |
// all resources associated with the loader should be released here. | |
} | |
private class DataObserverReceiver extends BroadcastReceiver { | |
final BaseAsyncTaskLoader<D> mLoader; | |
public DataObserverReceiver() { | |
mLoader = BaseAsyncTaskLoader.this; | |
IntentFilter filter = new IntentFilter(mIntentFilterAction); | |
mLoader.getContext().registerReceiver(this, filter); | |
} | |
@Override | |
public void onReceive(Context context, Intent intent) { | |
// does the following | |
// (a) forces a new load if the Loader is in a started state | |
// or... | |
// (b) raises a flag indicating that a change has been made so that if the Loader is ever started again, | |
// it will know that it should reload its data immediately | |
mLoader.onContentChanged(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment