Background Tasks – Part 4

In the previous article we had a look at AsyncTask as saw how it simplified the process of performing background tasks, but saw some potential pitfalls to the newbie, and also saw how it leaves the potential to leak a Context. In Honeycomb Loader was introduced and in this article we’ll have a look at what this offers us.

Before we continue, it is worth pointing out that although Loader was introduced in Honeycomb (API 11) it is also included in the Support Library, so it can be used in older projects as well. One problem that you’ll have pre Honeycomb is that you must extend FragmentActivity rather than Activity in order to get an instance of LoaderManager. Personally I don’t see this as a problem. I tend to use Fragments everywhere because they offer some useful functionality even when I don’t need them to provide different Layouts / UI for tablet & phone form factors. However, that’s a discussion for another article…

The Loader mechanism is specifically geared toward loading content either from a SQLite database, file storage, or from a network resource as a background task. That said, it can be used quite effectively to perform other tasks as well.

There are essentially three components that we need:

LoaderManager – this manages one or more Loader instances

Loader – this is the actual workhorse that will perform your background task

LoaderManager.LoaderCallbacks – this is an interface that you need to implement to manage the lifecycle of the Loader

In order to user a Loader, the first thing that you need to do is obtain a LoaderManager instance. This can be done from an Activity object (but only on API 11 or later), or through Fragment or FragmentActivity (either the native ones in API 11 or later, or using the Support Library classes in earlier versions):

The next thing that we must do is implement LoaderManager.LoaderCallbacks which are callback methods which will create a loader, and get called when the loader either finishes, or is reset. These will all be executed on the UI thread, and we will typically implement them within our Activity / FragmentActivity. The simple fact that we implement these in a separate class from the Loader provides a logical separation between the code which runs on the UI thread and that which runs on the background thread because they are in separate classes. This reduces the risk of running into the issue we discussed in the previous article of running a network call in the wrong method of AsyncTask. The simple fact that the methods invoked on the UI thread are implemented within our Activity / FragmentActivity is a strong hint that we shouldn’t be doing anything too heavy in them and make sure that code goes in to the Loader itself.

So our Activity looks like this:

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

publicclassLoaderActivity

extendsActivity

implementsLoaderCallbacks<String>

{

@Override

publicvoidonCreate(Bundle savedInstanceState)

{

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

LoaderManager lm=getSupportLoaderManager();

Loader<String>loader=lm.restartLoader(0,

null,this);

loader.forceLoad();

}

@Override

publicLoader<String>onCreateLoader(intid,

Bundle args)

{

returnnewMyLoader(this);

}

@Override

publicvoidonLoadFinished(Loader<String>loader,

Stringstr)

{

Toast.makeText(this,str,

Toast.LENGTH_SHORT).show();

}

@Override

publicvoidonLoaderReset(Loader<String>loader)

{

}

}

Actually implementing things is actually quite similar to what we have to do for AsyncTask. There is actually an AsyncTaskLoader class which we can extend which is based upon AsyncTask. All we have to do is implement the doInBackground() method exactly as we would for AsyncTask:

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

publicclassMyLoaderextendsAsyncTaskLoader<String>

{

publicMyLoader(Context context)

{

super(context);

}

@Override

publicStringloadInBackground()

{

Stringret=null;

// Do something which

// populates ret

returnret;

}

}

I have only scratched the surface on what you can do with Loaders, but there are some really good tutorials an samples on developer.android.com.

In the next part of this series we’ll change tack a little and have a look at when and how to use Services to perform your background processing.