1

Can anyone point me to a simple example of using a CursorLoader to query a SQLite database and populate a ListFragment? The code below will compile, but when I run it, LogCat tells me that "ListFrag" cannot be cast LoaderManager.LoaderCallbacks. If I change ListFrag so that it's not ListFrag, just ListFrag, I'm told that "ListFrag cannot be cast to android.v4.support.Fragment". Note that my activity extends FragmentActivity and my Fragment extends ListFragment because of the information in this forum post. I've been struggling with getting this to work for a while now and I just don't get it. Here's my code for the activity which contains the fragment and thank you:

import android.os.Bundle;
import android.support.v4.app.FragmentActivity

public class MyList extends FragmentActivity {
public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.myfragment);
}
}

And here's my code for the fragment:

import android.app.ListFragment;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.CursorAdapter;
import android.support.v4.widget.SimpleCursorAdapter;
import android.support.v4.app.LoaderManager;
import android.view.View;
import android.widget.ListView;

@SuppressWarnings("hiding")
public class ListFrag<Cursor> extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> {   
    private static final String TABLE_BASEPATH = "MyTable_tbl";
    private static final String AUTHORITY = "SQLData";
    public static final Uri MY_URI = Uri.parse("content://" + AUTHORITY + "/" + TABLE_BASEPATH);
    private static final String[] PROJECTION = new String[] { "_id", "fieldname" };
    private SimpleCursorAdapter mAdapter;
    private static final int LOADER_ID = 0;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @SuppressWarnings("unchecked")
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        Intent myData = getActivity().getIntent();
        Bundle info = myData.getExtras();


            SimpleCursorAdapter adapter;
            String[] dataColumns = { "fieldname" };
            int[] viewIDs = { R.id.mydetails };
            adapter = new SimpleCursorAdapter(getActivity(), R.layout.mylist, null, dataColumns, viewIDs, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
            setListAdapter(adapter);
            getLoaderManager().initLoader(0, info, (LoaderCallbacks<Cursor>) this); 

    }

          @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        String item = (String) getListAdapter().getItem(position);
        DetailFrag frag = (DetailFrag) getFragmentManager().findFragmentById(R.id.frag_detail);
        if (frag != null && frag.isInLayout()) {
            frag.setText(item);
        }
    }

    @SuppressWarnings("unchecked")
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        String selection = "level='" + args.getString("Level") + "'";
        return (Loader<Cursor>) new CursorLoader(getActivity(), MY_URI,
                PROJECTION, selection, null, null); 
    }
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        switch (loader.getId()) {
          case LOADER_ID:
            mAdapter.swapCursor((android.database.Cursor) cursor);
            break;
        }


    }
    public void onLoaderReset(Loader<Cursor> loader) {
        mAdapter.swapCursor(null);

    }

}

Just saw your comment about LogCat. Oops. Here's my entire LogCat:

11-05 15:47:27.953: D/dalvikvm(553): Not late-enabling CheckJNI (already on)
11-05 15:47:28.643: I/dalvikvm(553): threadid=3: reacting to signal 3
11-05 15:47:28.683: I/dalvikvm(553): Wrote stack traces to '/data/anr/traces.txt'
11-05 15:47:29.143: I/dalvikvm(553): threadid=3: reacting to signal 3
11-05 15:47:29.153: I/dalvikvm(553): Wrote stack traces to '/data/anr/traces.txt'
11-05 15:47:29.643: I/dalvikvm(553): threadid=3: reacting to signal 3
11-05 15:47:29.653: I/dalvikvm(553): Wrote stack traces to '/data/anr/traces.txt'
11-05 15:47:30.143: I/dalvikvm(553): threadid=3: reacting to signal 3
11-05 15:47:30.153: I/dalvikvm(553): Wrote stack traces to '/data/anr/traces.txt'
11-05 15:47:30.643: I/dalvikvm(553): threadid=3: reacting to signal 3
11-05 15:47:30.693: D/gralloc_goldfish(553): Emulator without GPU emulation detected.
11-05 15:47:30.693: I/dalvikvm(553): Wrote stack traces to '/data/anr/traces.txt'
11-05 15:47:32.843: E/ActivityThread(553): Failed to find provider info for SQLData
11-05 15:47:32.883: D/AndroidRuntime(553): Shutting down VM
11-05 15:47:32.883: W/dalvikvm(553): threadid=1: thread exiting with uncaught exception    (group=0x409c01f8)
11-05 15:47:32.903: E/AndroidRuntime(553): FATAL EXCEPTION: main
11-05 15:47:32.903: E/AndroidRuntime(553): java.lang.NullPointerException
11-05 15:47:32.903: E/AndroidRuntime(553):  at com.MyKnitCards.project.ListFrag.onLoadFinished(ListFrag.java:71)
11-05 15:47:32.903: E/AndroidRuntime(553):  at android.support.v4.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:425)
11-05 15:47:32.903: E/AndroidRuntime(553):  at android.support.v4.app.LoaderManagerImpl$LoaderInfo.onLoadComplete(LoaderManager.java:393)
11-05 15:47:32.903: E/AndroidRuntime(553):  at android.support.v4.content.Loader.deliverResult(Loader.java:103)
11-05 15:47:32.903: E/AndroidRuntime(553):  at android.support.v4.content.CursorLoader.deliverResult(CursorLoader.java:81)
11-05 15:47:32.903: E/AndroidRuntime(553):  at android.support.v4.content.CursorLoader.deliverResult(CursorLoader.java:35)
11-05 15:47:32.903: E/AndroidRuntime(553):  at android.support.v4.content.AsyncTaskLoader.dispatchOnLoadComplete(AsyncTaskLoader.java:221)
11-05 15:47:32.903: E/AndroidRuntime(553):  at android.support.v4.content.AsyncTaskLoader$LoadTask.onPostExecute(AsyncTaskLoader.java:61)
11-05 15:47:32.903: E/AndroidRuntime(553):  at android.support.v4.content.ModernAsyncTask.finish(ModernAsyncTask.java:461)
11-05 15:47:32.903: E/AndroidRuntime(553):  at android.support.v4.content.ModernAsyncTask.access$500(ModernAsyncTask.java:47)
11-05 15:47:32.903: E/AndroidRuntime(553):  at android.support.v4.content.ModernAsyncTask$InternalHandler.handleMessage(ModernAsyncTask.java:474)
11-05 15:47:32.903: E/AndroidRuntime(553):  at android.os.Handler.dispatchMessage(Handler.java:99)
11-05 15:47:32.903: E/AndroidRuntime(553):  at android.os.Looper.loop(Looper.java:137)
11-05 15:47:32.903: E/AndroidRuntime(553):  at android.app.ActivityThread.main(ActivityThread.java:4424)
11-05 15:47:32.903: E/AndroidRuntime(553):  at java.lang.reflect.Method.invokeNative(Native Method)
11-05 15:47:32.903: E/AndroidRuntime(553):  at java.lang.reflect.Method.invoke(Method.java:511)
11-05 15:47:32.903: E/AndroidRuntime(553):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
11-05 15:47:32.903: E/AndroidRuntime(553):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
11-05 15:47:32.903: E/AndroidRuntime(553):  at dalvik.system.NativeStart.main(Native Method)
11-05 15:47:33.213: I/dalvikvm(553): threadid=3: reacting to signal 3
11-05 15:47:33.233: I/dalvikvm(553): Wrote stack traces to '/data/anr/traces.txt'
11-05 15:47:33.513: I/dalvikvm(553): threadid=3: reacting to signal 3
11-05 15:47:33.533: I/dalvikvm(553): Wrote stack traces to '/data/anr/traces.txt'
Community
  • 1
  • 1
Melanie
  • 3,021
  • 6
  • 38
  • 56
  • this tutorial: http://mobile.tutsplus.com/tutorials/android/android-sdk_loading-data_cursorloader/ give a good overview of combining ListFragments with CursorAdapters – Thomas Nov 15 '13 at 12:01

2 Answers2

3

First try switching these imports to the support library versions. Change:

import android.app.ListFragment;
import android.app.LoaderManager.LoaderCallbacks;

to:

import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager.LoaderCallbacks;

Next make sure you are asking for the support fragment manager:

DetailFrag frag = (DetailFrag) getActivity().getSupportFragmentManager().findFragmentById(R.id.frag_detail);
//                                              ^^^^^^^

(This might not solve everything, if you still need help post the LogCat errors from these changes so we can see exactly what is happening.)


Addition mAdapter is null, change adapter to mAdapter here:

mAdapter = new SimpleCursorAdapter(getActivity(), R.layout.mylist, null, dataColumns, viewIDs, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
Sam
  • 86,580
  • 20
  • 181
  • 179
  • Thanks for the speedy response! I made the two changes to the imports you suggested, but changing getFragmentManager to getSupportFragmentManager would not compile. The error was, "getSupportFragmentManager() is undefined for type ListFrag". Changing my class name to just ListFrag didn't help. So, with the two imports pointing to the Support Library and calling getFragmentManager, I'll post my LogCat in the next comment – Melanie Nov 05 '12 at 20:52
  • Add the LogCat to your question with "edit" (in its lower left corner), comments don't format well... – Sam Nov 05 '12 at 20:53
  • OK, I can't post my entire LogCat; it's too long, but there is this line: 11-05 15:47:32.843: E/ActivityThread(553): Failed to find provider info for SQLData. Does that give us a clue? SQLData is my class that defines the SQLite database. Alternatively, I can post my entire LogCat as an answer to the question, but I'm not sure that's allowed. Please advise and thanks! – Melanie Nov 05 '12 at 20:56
  • OK, just I put the LogCat in the initial question. – Melanie Nov 05 '12 at 21:00
  • Hmm, that's a error with your ContentProvider. I searched for "Failed to find provider info for" and [this might help](http://stackoverflow.com/q/7463118/1267661). – Sam Nov 05 '12 at 21:00
  • 1
    I noticed that you are accidentally using `SimpleCursorAdapter adapter` not `mAdapter` in `onCreate()`, my new answer shows what to change. What's next? :) – Sam Nov 05 '12 at 21:07
  • Hmmm... My understanding is that I only need a ContentProvider if I want to share data between applications. That's not the case here. I just have a database (which I create earlier) that I want to query. Or am I misunderstanding something? – Melanie Nov 05 '12 at 21:10
  • Yes, SimpleCursorAdapter instead of mAdapter was the problem! It works now, although I'm not getting any data. :( But that's something else to dig into. Thank you SO much! – Melanie Nov 05 '12 at 21:22
  • You're welcome. Though looking at the CursorLoader class I can see [`loadInBackground()`](http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.1.1_r1/android/content/CursorLoader.java#CursorLoader.loadInBackground%28%29) relies on a ContentProvider... – Sam Nov 05 '12 at 21:28
  • OK, I'll look at that. I'm not using loadInBackground, so maybe it doesn't matter. I'll admit I'm totally confused on the subject of whether I need a ContentProvider or not. Thanks again. – Melanie Nov 05 '12 at 21:38
0

You should check Sherlock, they offer different versions of loaders working with fragments. You just have to download their package and inside you can find the samples working.

Ups, I just saw this is seven months old. Hope it is still usefull.

Dieglock
  • 169
  • 1
  • 16
  • For some reason I never got an email notifying me of your answer. I just noticed it today. I'll take a look at Sherlock and vote you up if it helps. Thank you! – Melanie Nov 15 '13 at 15:29
  • ;). if you like Ruby, you should also check Ruboto. Might facilitate a lot the databases managment. – Dieglock Nov 15 '13 at 20:52