Before starting Loader I will recommend you all to get a
brief about Fragments which are introduced in Android API level 11 (i.e.
HoneyComb).
Loader is introduced in Android 3.0, loaders make it easy
to asynchronously load data in an activity or fragment. Loaders have these
characteristics:
·
They are available to every Activity and
Fragment.
·
They provide asynchronous loading of data.
·
They monitor the source of their data and
deliver new results when the content changes.
·
They automatically reconnect to the last
loader's cursor when being recreated after a configuration change. Thus, they
don't need to re-query their data.
Dealing with Loader you may came across to the
classes/interfaces LoaderManager, LoaderManager.LoaderCallbacks, Loader,
AsyncTaskLoader, CursorLoader.
The LoaderManager manages one or more Loader
instances within an Activity or Fragment. There is only one LoaderManager per
activity or fragment.
Starting
a Loader¶
Loader should be initialized within the activity's
onCreate() method, or within the fragment's onActivityCreated() method using
initLoader() method.
The initLoader() method takes the following parameters:
·
A unique ID that identifies the loader. In this
example, the ID is 0.
·
Optional arguments to supply to the loader at
construction (null in this example).
·
A LoaderManager.LoaderCallbacks implementation,
which the LoaderManager calls to report loader events. In this example, the
local class implements the LoaderManager.LoaderCallbacks interface, so it
passes a reference to itself, this.
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0,
null, this);
Restarting
a Loader¶
When you use initLoader(), as shown above, it uses an
existing loader with the specified ID if there is one. If there isn't, it
creates one. But sometimes you want to discard your old data and start over.
To discard your old data, you use restartLoader().
getLoaderManager().restartLoader(0, null,
this);
Using the LoaderManager Callbacks¶
LoaderManager.LoaderCallbacks is a callback interface that
lets a client interact with the LoaderManager.
Loaders, in particular CursorLoader, are expected to
retain their data after being stopped. This allows applications to keep their
data across the activity or fragment's onStop() and onStart() methods, so that
when users return to an application, they don't have to wait for the data to
reload. You use the LoaderManager.LoaderCallbacks methods when to know when to
create a new loader, and to tell the application when it is time to stop using
a loader's data.
LoaderManager.LoaderCallbacks includes these methods:
·
onCreateLoader() — Instantiate and return a new
Loader for the given ID.
·
onLoadFinished() — Called when a previously
created loader has finished its load.
·
onLoaderReset() — Called when a previously
created loader is being reset, thus making its data unavailable.
These methods are described in more detail in the
following sections.
onCreateLoader
When you attempt to access a loader (for example, through
initLoader()), it checks to see whether the loader specified by the ID exists.
If it doesn't, it triggers the LoaderManager.LoaderCallbacks method
onCreateLoader(). This is where you create a new loader. Typically this will be
a CursorLoader, but you can implement your own Loader subclass.
onLoadFinished
This method is called when a previously created loader has
finished its load. This method is guaranteed to be called prior to the release
of the last data that was supplied for this loader. At this point you should
remove all use of the old data (since it will be released soon), but should not
do your own release of the data since its loader owns it and will take care of
that.
onLoaderReset
This method is called when a previously created loader is
being reset, thus making its data unavailable. This callback lets you find out
when the data is about to be released so you can remove your reference to it.
I will explain you how to use Loader in your app.And as I
have mentioned you should have a little idea about the Fragments.
Step 1 : Create an android
project and Activity¶
Create an Activity name
FragmentListCursorLoader
Write following code in your onCreate() method
FragmentManager fm = getFragmentManager();
//
Create the list fragment and add it as our sole content.
if
(fm.findFragmentById(android.R.id.content) == null) {
CursorLoaderListFragment
list = new CursorLoaderListFragment();
fm.beginTransaction().add(android.R.id.content,
list).commit();
}
Where getFargmentManager is the method defined in Activity
Class.
Step 2 : Create
CursorLoaderListFragment class¶
CursorLoaderListFragment is the class which will retrieve
Contacts from Android Device and will display on the screen using Loader.
CursorLoaderListFragment has extended ListFragment and two
interfaces named CursorLoaderListFragment and
LoaderManager.LoaderCallbacks<Cursor>
Step 3 : Write
onActivityCreateMethod :¶
// Give
some text to display if there is no data.
In a real
//
application this would come from a resource.
setEmptyText("No
phone numbers");
// We
have a menu item to show in action bar.
setHasOptionsMenu(true);
//
Prepare the loader. Either re-connect
with an existing one,
// or
start a new one.
getLoaderManager().initLoader(0,
null, this);
Now in this method there are three lines which I need to
explain you.
1) setEmptyText will display the content which is passed in argument only when
there is no data to diplay.
2) setHasOptionMenu will indicate whether to show the optionMenu content in the
Activity or not.
3) getLoaderManager().initLoader(0, null, this); will init the loader. We need
to give the unique Id to the initLoader, for our example it is 0.
Step
4 : What Loader will do.¶
public Loader<Cursor> onCreateLoader(int id,
Bundle args) {
//
This is called when a new Loader needs to be created. This
//
sample only has one Loader, so we don't care about the ID.
//
First, pick the base URI to use depending on whether we are
//
currently filtering.
Uri
baseUri;
if
(mCurFilter != null) {
baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
Uri.encode(mCurFilter));
} else {
baseUri = Contacts.CONTENT_URI;
}
//
Now create and return a CursorLoader that will take care of
//
creating a Cursor for the data being displayed.
String
select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("
+ Contacts.HAS_PHONE_NUMBER + "=1) AND ("
+ Contacts.DISPLAY_NAME + " != '' ))";
return
new CursorLoader(getActivity(), baseUri,
CONTACTS_SUMMARY_PROJECTION, select, null,
Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
}
As you can see the task which a Loader should perform is
written in onCreateLoader method.
It needs...
·
uri — The URI for the content to retrieve.
·
projection — A list of which columns to return.
Passing null will return all columns, which is inefficient.
·
selection — A filter declaring which rows to
return, formatted as an SQL WHERE clause (excluding the WHERE itself). Passing
null will return all rows for the given URI.
·
selectionArgs — You may include ?s in the
selection, which will be replaced by the values from selectionArgs, in the
order that they appear in the selection. The values will be bound as Strings.
·
sortOrder — How to order the rows, formatted as
an SQL ORDER BY clause (excluding the ORDER BY itself). Passing null will use
the default sort order, which may be unordered.
Step 5 : Time to close the Loader
The loader will release the data once it knows the
application is no longer using it. For example, if the data is a cursor from a
CursorLoader, you should not call close() on it yourself. If the cursor is
being placed in a CursorAdapter, you should use the swapCursor() method so that
the old Cursor is not closed. For example:
public void onLoadFinished(Loader<Cursor>
loader, Cursor data) {
// Swap the
new cursor in. (The framework will take
care of closing the
// old
cursor once we return.)
mAdapter.swapCursor(data);
}
Step
6 : Reset the Loader
This callback lets you find out when the data is about to
be released so you can remove your reference to it.
public void onLoaderReset(Loader<Cursor>
loader) {
// This is
called when the last Cursor provided to onLoadFinished()
// above is
about to be closed. We need to make sure
we are no
// longer
using it.
mAdapter.swapCursor(null);
}
You will also find method to create Menu and request
search query also..
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
//
Place an action bar item for searching.
MenuItem
item = menu.add("Search");
item.setIcon(android.R.drawable.ic_menu_search);
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
SearchView
sv = new SearchView(getActivity());
sv.setOnQueryTextListener(this);
item.setActionView(sv);
}
public boolean onQueryTextChange(String newText) {
//
Called when the action bar search text has changed. Update
// the
search filter, and restart the loader to do a new query
// with this filter.
mCurFilter
= !TextUtils.isEmpty(newText) ? newText : null;
getLoaderManager().restartLoader(0,
null, this);
return
true;
}
I have attached demo project which has two different
Activities. You can see it one by one for better understanding of the Loader.