I'm trying to make a ContentProvider
with each record containing a question and corresponding answer. And an Activity showing TextViews of each question and answer and a "Next" button below those TextViews. When the Next button is clicked I would like the next question and answer to show.
I'm trying to use a CursorLoader and LoaderManager, because the CursorLoaders keep their data across onStop()
and onStart()
, and I am trying to learn about CursorLoaders
and LoaderManagers
.
The examples I have found all use setListAdapter()
, but I don't want my activity to look like a list. I've tried to go around this by using a SimpleCursorAdapter
and using bindView()
to my main.xml
layout. Not sure that is going to work.
If I had a plain Cursor I would use moveToNext()
, but for a LoaderManager
it seems I have to restartLoader()
with a new query. I think creating a new query would cost more time than simply going to the next record with a cursor. Especially since I would have to know the position of the current or next record.
So my question is: Can I use a CursorLoader
and LoaderManager
to go through a database, record by record without having to make a new query for the next record? Or are CursorLoaders
and LoaderManagers
really only for ListViews?
Here is my code so far, I realize it's not much, but I have read and re-read Android's pages on Loaders and LoadManagers.
public class Main extends Activity implements LoaderManager.LoaderCallbacks<Cursor>{
SimpleCursorAdapter adapter;
String curFilter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
this.adapter = new SimpleCursorAdapter(getApplicationContext(),
R.layout.main,
null,
new String[]{},
new int[]{R.id.questionText,R.id.answerText},
0);
LinearLayout mainLayout = (LinearLayout)findViewById(R.id.mainLayout);
this.adapter.bindView(mainLayout, getApplicationContext(), null);
this.getLoaderManager().initLoader(0,null, this);
Button nextQuestionButton = (Button)this.findViewById(R.id.Nextbutton);
nextQuestionButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick (View v) {
}
});
}
I understand that my question was vague, I was really lost. Here's my answer, many months later, hope it helps someone who is in my past position.
onCreateLoader() is automatically called when I call getLoaderManager().initLoader() or when there has been a change to the content provider (content provider has to call getContentResolver().notifyChange() for this to work). I provide the code to make the cursor loader when overwriting the method LoaderManager.LoaderCallbacks.onCreateLoader(). The cursor loader is automatically handed to onLoadFinished(). That's it, I don't touch the cursor loader again. onLoadFinished(), which is called automatically, receives a cursor (made from the cursor loader) as an argument. I update the adapter in my override of onLoadFinished() using the cursor argument, this.adapter.setCursor(cursor).
SimpleCursorAdapter doesn't have a moveToNext or moveToPrevious, so I made a SteppedAdapter, see below:
public class SteppedAdapter {
private Cursor cursor = null;
// This class uses a reference which may be changed
// by the calling class.
public SteppedAdapter (Cursor cursor) {
this.cursor = cursor;
}
private int getColumnIndexOrThrow (String columnName) {
return cursor.getColumnIndexOrThrow(columnName);
}
public void moveToNext () {
if (null != cursor && !cursor.isClosed()) {
if (cursor.isLast()) {
cursor.moveToFirst();
}
else {
cursor.moveToNext();
}
}
}
public void moveToPrevious () {
if (null != cursor && !cursor.isClosed()) {
if (cursor.isFirst()) {
cursor.moveToLast();
}
else {
cursor.moveToPrevious();
}
}
}
public String getCurrentTarget (String targetColumn) throws EmptyCursorException {
int idx = cursor.getColumnIndex(targetColumn);
String value = null;
try {
value = cursor.getString(idx);
}
catch (CursorIndexOutOfBoundsException e){
if ( 0 == cursor.getCount()) {
throw new EmptyCursorException("Cursor is empty: "+e.getMessage());
}
else {
throw e;
}
}
return value;
}
public void setCursor (Cursor cursor) {
this.cursor = cursor;
}
public void setCursorToNull () {
this.cursor = null;
}
public int getPosition () {
return this.cursor.getPosition();
}
public boolean cursorIsClosed () {
return this.cursor.isClosed();
}
public int getCount () {
return cursor.getCount();
}
} // end
Since the adapter is set in onLoadFinished() using the method adapter.setCursor(Cursor), and cleared in onLoaderReset() using the method adapter.setCursorToNull(). Then the adapter has to have these methods.