If anyone finds themselves in a similar situation, here's what I've done:
- Created a class which implements
LoaderCallbacks
and handles all the queries you'll need.
- Supply this with a
Context
and the Adapter
in question.
- Create unique IDs for each query you'll use (if you use a
UriMatcher
, might as well use the same ones)
- Make a convenience method which transfers queries into the bundle required for the
LoaderCallbacks
- That's pretty much it :) I put some of my code below to show exactly what I did
In my GlobalCallbacks
class:
public static final String PROJECTION = "projection";
public static final String SELECTION = "select";
public static final String SELECTARGS = "sargs";
public static final String SORT = "sort";
Context mContext;
SimpleCursorAdapter mAdapter;
public GlobalCallbacks(Context context, SimpleCursorAdapter adapter) {
mContext = context;
mAdapter = adapter;
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
Uri contentUri = AbsProvider.customIntMatch(id);
if (contentUri != null) {
return new CursorLoader(mContext, contentUri, args.getStringArray(PROJECTION), args.getString(SELECTION),
args.getStringArray(SELECTARGS), args.getString(SORT));
} else return null;
}
@Override
public void onLoadFinished(Loader<Cursor> arg0, Cursor arg1) {
mAdapter.swapCursor(arg1);
}
@Override
public void onLoaderReset(Loader<Cursor> arg0) {
mAdapter.swapCursor(null);
}
And when I wanted to use a CursorLoader
(Helper.bundleArgs()
is the convenience bundling method):
scAdapt = new Adapters.NewIndexedAdapter(mHost, getMenuType(),
null, new String[] { "name" }, new int[] { android.R.id.text1 });
getLoaderManager().initLoader(
GlobalCallbacks.GROUP,
Helper.bundleArgs(new String[] { "_id", "name" }),
new GlobalCallbacks(mHost, scAdapt));
setListAdapter(scAdapt);
And in Helper:
public static Bundle bundleArgs(String[] projection, String selection, String[] selectionArgs) {
Bundle b = new Bundle();
b.putStringArray(GlobalCallbacks.PROJECTION, projection);
b.putString(GlobalCallbacks.SELECTION, selection);
b.putStringArray(GlobalCallbacks.SELECTARGS, selectionArgs);
return b;
}
Hope this helps someone else :)
EDIT
To explain more thoroughly:
- First, an adapter with a null
Cursor
is initialised. We don't supply it with a Cursor
because GlobalCallbacks
will give the adapter the correct Cursor
in onLoadFinished(..)
- Next, we tell
LoaderManager
we want to initialise a new CursorLoader
. We supply a new GlobalCallbacks
instance (which implements Loader.Callbacks
) which will then monitor the loading of the cursor. We have to supply it with the adapter too, so it can swap in the new Cursor
once its done loading. At some point, the LoaderManager
(which is built into the OS) will call onCreateLoader(..)
of GlobalCallbacks
and start asynchronously loading data
Helper.bundleArgs(..)
just puts arguments for the query into a Bundle
(e.g. columns projection, sort order, WHERE clause)
- Then we set the
Fragment
's ListAdapter
. The cursor will still be null at this point, so it will show a loading sign or empty message until onLoadFinished()
is called
initLoader()
mean to be unique or each set of data you need to query? And because I have multiple activities which each use different tables of my database, is there any way I can create a class which handles eachCursorLoader
, much like aContentProvider
can handle multipleCursors
withquery
? – Provoke