I'm trying to implement a DataListFragment with an adapter that uses a Loader from Commonsware. This Loader uses a SQLiteDatabase directly and doesn't require the use of ContentProviders.
The android reference states about Loaders: "While Loaders are active they should monitor the source of their data and deliver new results when the contents change."
Under my SQLiteCursor implementation (below), this does not happen. OnLoadFinished()
gets called once and that's it. Presumably, one could insert Loader.onContentChanged()
calls where the underlying database gets changed, but in general the database code class does not know about loaders, so I'm not sure about the best way to go about implementing this.
Does anyone have any advice on making the Loader "data aware", or should I wrap the database stuff in as a ContentProvider and use CursorLoader instead?
import com.commonsware.cwac.loaderex.SQLiteCursorLoader;
public class DataListFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor>{
protected DataListAdapter mAdapter; // This is the Adapter being used to display the list's data.
public SQLiteDatabase mSqlDb;
private static final int LOADER_ID = 1;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
int rowlayoutID = getArguments().getInt("rowLayoutID");
// Create an empty adapter we will use to display the loaded data.
// We pass 0 to flags, since the Loader will watch for data changes
mAdapter = new DataListAdapter(getActivity(),rowlayoutID, null , 0);
setListAdapter(mAdapter);
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
LoaderManager lm = getLoaderManager();
// OnLoadFinished gets called after this, but never again.
lm.initLoader(LOADER_ID, null, this);
}
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String sql="SELECT * FROM "+TABLE_NAME+";";
String[] params = null;
SQLiteCursorLoader CursorLoader = new SQLiteCursorLoader(getActivity(), mSqlDb, sql, params);
return CursorLoader;
}
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);
// The list should now be shown.
if (isResumed()) { setListShown(true);}
else { setListShownNoAnimation(true); }
}
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);
}
The
Loader
documentation is flawed.100% of
Loader
implementations built into Android itself "monitor the source of their data and deliver new results when the contents change". Since there is only oneLoader
implementation built into Android itself as of now, their documentation is accurate as far as that goes.However, quoting a book update of mine that should be released in an hour or two:
I do plan on augmenting
SQLiteCursorLoader
to be at least a bit more aware of database changes, if you route all database modifications through it. That too will have limitations, because you don't shareLoader
objects between activities (let alone have access to them from services).The only reason
CursorLoader
works as it does is because it uses aContentProvider
-- a singleton that can therefore be aware of all operations.At the moment, whatever portion of your code is responsible for inserts, updates, and deletes will either need to tap the
SQLiteCursorLoader
on the shoulder and have it update, or notify the activity of the change (e.g., broadcast from aService
) so the activity can tap theSQLiteCursorLoader
on the shoulder.