With the Introduction of Android 3.0 Honeycomb, came a lot of new features, but one I really have found useful is the implementation of Loaders. Loaders provide the basis for loading data in the background, weather it is from an SQLite Database, Images from a webservice or just a shit-load of items into a list a Loader's are the way to go!
While only a mere 4.4% of Android devices are on 3.0 or higher (as of Feb 1st 2012), Loaders were added to the Android Compatibility Library provides support all the way back to 1.6 (as does Jake Whorton's Action Bar Sherlock library). That's right, support all the way back to DONUT! (Yum) Not only are they super useful, but they are super easy to use. Here's how to go about it:
First you need to add the compatibility library (or ABS) to your project if you're going to be using anything less than Android 3.0. Next, you need to build your loader. While the
Loader
class is the abstract class, it does not inherently provide multi-thread support for asynchronous loading. It's best to either use a CursorLoader
or extend from AsyncTaskLoader
. Obviously if you're loading data from a database or ContentProvider
then a CursorLoader
is what you're looking for. Most cases, however, you'll want to implement your own Loader class that extends from AsyncTaskLoader
. There are a few things to make sure you watch out for when implementing your custom loader:- While loading your data, check to see if the Loader was cancelled. The easiest way to do this is to add a
boolean
object to your Loader that you can check, and set the appropriate value in your Loader'sonCancelled()
method orcancelLoad()
method. ThecancelLoad()
method attempts to callcancel()
on the built inAsyncTask
, but it's nice to tell your own load that it's time to stop. - You must initiate the load from somewhere in your Loader. A great place to do this is in the
onStartLoading()
method, and all you have to do is callforceLoad()
. - Check if you already have your data loaded when a request to
onStartLoading()
is called, and you can save time and possible data by just delivering the result you already loaded once. - Clear your cached data in
onReset()
and to release any resources you can (closing cursors and the sort) since this means someone wants fresh data.
AsyncTaskLoader
implementation:import android.content.AsyncTaskLoader; // Import android.support.v4.content.AsyncTaskLoader if using the compatability library public class MyAsyncLoader extends AsyncTaskLoader{ // MyDataType can be anything (lookup Java Generics) including Arrays or JSONObects private MyDataType mData; // This is essentially our "cache" private boolean mCancelled = false; //So we can check if we need to stop loading, not always required. // We have to have a constructor that calls super(Context) public MyAsyncLoader(Context ctx) { super(ctx); } @Override public void onCancelled() { // Attempt to cancel our asynctask cancelLoad(); mCancelled = true; // Don't need any data mData = null; } // This get's called after a loader is initialized or a loader that is alive still is reset @Override public void onStartLoading() { mCancelled = false; if( mData != null) { // Have our data loaded, just deliver it! deliverResult(mData); return; } forceLoad(); // This starts the AsyncTask that will load our data. } //This is called when an Activity or Fragment requests a loader to be reset because they want new data @Override public void onReset() { mData = null; cancelLoad(); // Ensure that the old task is cancelled if it was running // We do NOT have to call forceLoad here because onStartLoading will get called after this } // Here we just want to store our own data we got and reset our boolean @Override public void deliverResult(MyDataType data) { mData = data; mCancel = false; // I'm pretty sure this is redundant, but I have it here anyway if( isStarted()) { // Only want to deliver the result if the loader wasn't stopped or cancelled. The super class can do the rest super.deliverResult(mData); } } // Now the last part!! @Override public MyDataType loadInBackground() { // Essentially this method is called from the built in AsyncTask of the parent class // Load our junk, and if possible check if mCancelled is true and abort loading if it is return loadedData; } } // end of MyAsyncLoader
Now that we have our Loader defined, we need to implement it in our
Activity
(or Fragment
. To do this, we use the LoaderManager
and LoaderManager.LoaderCallBacks
. You can implement the callbacks on the Activity itself, using a seperate class or as an anonymous inner class. The 3 callbacks you need to use are:- onCreateLoader()
- onLoadFinished()
- onLoaderReset()
onCreateLoader
and onLoaderReset
methods and then clear it in onLoadFinished()
, which I've done in the example below. Then you use the LoaderManager
to start and reset your Loader. Here's an example:import android.app.Activity; //if using the support library use android.support.v4.app.FragmentActivity import android.app.LoaderManager.LoaderCallbacks; // if using support lib use android.support.v4.app.LoaderManager.LoaderCallbacks public class MyLoaderActivity extends Activity implements LoaderManager.LoaderCallbacks{ private MyDataType mLoadedData; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(Bundle savedInstanceState); // We're going to use the built in title bar/action bar progress indicator requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); setContentView(R.layout.mylayout); // Use the LoaderManager to load our data in the background // If using the support library call getSupportLoaderManager() instead getLoaderManager.initLoader(0, null, this); // Arguments are (ID of the loader, optional Bundle of arguments, Callbacks) } //Loader Callbacks public LoaderonCreateLoader(int id, Bundle args) { // Since we only have one type of data and loader, we don't care about the id // We also don't use any arguments (you can create other constructors to take arguments into your loader (URLs, data types, etc) // We do want to start our progress bar though setProgressBarIndeterminateVisibility(true); return new MyAsyncLoader(this); } public void onLoaderReset(Loaderloader) { // Again, start the progress bar setProgressBarIndeterminateVisibility(true); mLoadedData = null; // Don't really care about the loader since we know what it was, everything else is already called by the framework. This would be a great place to clear ListAdapters or whatnot if you don't want old data visible. } public void onLoadFinished(MyDataType data) { //Turn off our progress bar setProgressBarIndeterminateVisibility(false); mLoadedData = data; // Do whatever else you need to here, like setting a ListAdapter, etc } } // End of MyLoaderActivity
That's all there is to it! Seems like a bit more than I had initially thought, but it's still pretty simple. Go and load to your hearts content!
Free Online Poker Tournaments | No Limit Texas Hold'em ボンズ カジノ ボンズ カジノ bk8 bk8 메리트카지노 메리트카지노 287Playtech QQ288 Review | Honest Casino & Slot Review
ReplyDelete