Search code examples
androidcursorandroid-cursoradapterandroid-cursorloader

Handling different queries in a ListView using a CursorLoader


I want to reflect data from various tables in a sqlite database at different times in a single ListView.

The initial query works fine, which goes like this:

  • I have a custom CursorAdapter class (AutoCursorAdapter extends CursorAdapter) which can display arbitrary data from a Cursor:
    • AutoCursorAdapter.newView() interrogates the cursor and constructs a view corresponding to the types of data in the columns.
    • AutoCursorAdapter.bindView() takes the data from the cursor and populates the view created in newView for each row of data in the cursor.
  • I also implement a loader in the owning Fragment as follows:

    public class MyFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>{
    ...
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
             ...
             mListView = ((ListView) view.findViewById(R.id.listview));
             mAdapter = new AutoCursorAdapter(getActivity());
             mListView.setAdapter(mAdapter);
             return view;
         }
    
         public void onStart() {
            super.onStart();
            // Prepare the loader.  Either re-connect with an existing one,
            // or start a new one.
            LoaderManager lm = getLoaderManager();
            Bundle args = getArguments();
            lm.initLoader(LOADER_ID, args, this);
        }
    
        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
            CursorLoader CursorLoader = new CursorLoader(getActivity());
            setupLoader(CursorLoader); //Sets the URI, projection etc. depending on app state
            return CursorLoader;
        }
    
        public void onLoaderReset(Loader<Cursor> loader) {
            mAdapter.swapCursor(null);
        }
    }
    

So far, so good. The data gets loaded on the initial run. Let's say it pulls and displays data from table A using URI_A.

But now the question is: How do I deal with the case where I want to switch over to displaying data from table B using URI_B in response to a user action?

  • Can I do this with a single Loader instance?

    1. If so how? For instance CursorLoader.setUri() does not trigger a reload.
    2. If not, how do I manage multiple loader instances properly?
  • Is this an instance where Loaders perhaps aren't the way to go?

Note: the question is not about reflected changes in the underlying DB in table A. This gets updated in the UI correctly already through the NotifyChange mechanism. This question is about changing the nature of the underlying query altogether.


Solution

  • Can I do this with a single Loader instance?

    I would not recommend it. Loaders have enough state that trying to change them significantly like this may be troublesome, and having more than one loader is not that big of a deal when they all return the same data type (e.g., Cursor).

    If not, how do I manage multiple loader instances properly?

    Use different IDs for them (second parameter on initLoader()), and create the right Loader in onCreateLoader() based on ID.