0

I have an SherlockFragmentActivity that is showing a few tabs. Each tab is ListFragment.

Each ListFragment is getting created like so:

ActionBar bar = getSupportActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
bar.setDisplayHomeAsUpEnabled(true);
bar.setDisplayShowTitleEnabled(true);

// users event list
bar.addTab(bar.newTab()
    .setTag("contacts_list")
    .setText(getString(R.string.list_contacts_header))
    .setTabListener(new TabListener<ContactListFragment>(
        this, getString(R.string.list_events_header), ContactListFragment.class, null)));

Then, each of the ListFragments are loaded like so:

public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    // database cursor containing all venues for this event
    venuesCursor = getDatasource().getAllVenues(((EventActivity) getActivity()).getEventId());

    // hand the cursor to the system to manage
    getActivity().startManagingCursor(venuesCursor);  

    // bind the columns of the cursor to the list
    String[] from = new String[] { VenuesDataSource.KEY_NAME, VenuesDataSource.KEY_DESCRIPTION };
    int[] to = new int[] { R.id.list_item_title, R.id.list_item_subtitle };

    cursorAdapter = new SimpleCursorAdapter(getActivity(), R.layout.list_item, venuesCursor, from, to);

    // retrieve the listview to populate
    ListView lv = (ListView) getActivity().findViewById(android.R.id.list);

    // set the adapter on the listview
    lv.setAdapter(cursorAdapter);

    // click event for each row of the list
    lv.setOnItemClickListener(new OnItemClickListener() {

        public void onItemClick(AdapterView<?> arg0, View view,
                int position, long id) {
            Cursor cursor = cursorAdapter.getCursor();
            cursor.moveToPosition(position);
            Toast.makeText(getActivity(), "Tapped row " + position + "!", Toast.LENGTH_SHORT).show();

        }
    });

    // Start out with a progress indicator.
    setListShown(false);

    // prepare the loader -- either re-connect with an existing one, or start a new one.
    // getLoaderManager().initLoader(0, null, this);

    // load the data
    getActivity().getSupportLoaderManager().initLoader(0, null, this);
}

Like I said, there are multiple tabs on this activity in the form of ListFragments. The issue I'm having is that when clicking on the tabs to select them, I get

E/AndroidRuntime(2519): java.lang.IllegalArgumentException: column 'name' does not exist

Which is wrong, I've used adb to view the database, the columns that its complaining about are 100% there, so it has to be something to do with not closing a cursor or something and when the above loads its actually using the wrong cursor.

EDIT: Adding CursorLoader Code

public static final class VenueCursorLoader extends SimpleCursorLoader {

    Context mContext;

    public VenueCursorLoader(Context context) {
        super(context);

        mContext = context;
    }

    @Override
    public Cursor loadInBackground() {
        Cursor cursor = null;
        VenuesDataSource datasource = new VenuesDataSource(mContext);

        // TODO: provide the event_id to the getAllVenues method
        cursor = datasource.getAllVenues(((EventActivity) mContext).getEventId());

        if (cursor != null) {
            cursor.getCount();
        }

        return cursor;
    }

}

Any help much appreciated..

Rabbott
  • 4,282
  • 1
  • 30
  • 53

1 Answers1

1

This question is essentially answered here

Basically everything you need to understand is outlined in the answer. There are several fixes you should make:


  • You should pass the CursorAdapter a null cursor to begin with. The LoaderManager will have the CursorLoader to perform the initial query for you. (see my answer above). Also note that the constructor you are currently using is deprecated. You should use this one instead (pass it 0 as the flag).

    cursorAdapter = new SimpleCursorAdapter( getActivity(), R.layout.list_item, null, from, to, 0);


  • Remove this line:

    getActivity().startManagingCursor(venuesCursor);
    

    The whole point of the LoaderManager is that it manages the cursor for you. You don't need to "hand the cursor to the system to manage"... that is exactly the job of the LoaderManager. :)


  • Because of the reasons I described in #1 and #2, it looks like this line of code is unnecessary:

    venuesCursor = getDatasource().getAllVenues(
            ((EventActivity) getActivity()).getEventId());
    

  • I'm also not sure why you are overriding onItemClick. Since you are using ListFragments, I suspect you want to be overriding onListItemClick instead.

  • I'm not sure why you have included these lines, but it looks like you want to remove them as well.

    Cursor cursor = cursorAdapter.getCursor();
    cursor.moveToPosition(position);
    

    For the most part, you shouldn't manipulate the adapter's cursor, as it is managed by the internal system and is bound to the LoaderManager.

Community
  • 1
  • 1
Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
  • THanks Alex, I'm going to make these changes later on today, I really appreciate your help -- I'll be back to accept the answer if it ends up working. To answer your 'not sure why' questions, well, because I started android dev last Thursday :) Learning as I go.. – Rabbott Jun 22 '12 at 17:53
  • if I remove those items you mentioned, how will the list be notified of what its supposed to display? (I also have this SimpleCursorLoader, maybe this is when I'm supposed to load the data, instead of in the onActivityCreated method) – Rabbott Jun 22 '12 at 18:06
  • Well at least you are starting off on the right path... most beginners are too lazy to attempt understanding how the `LoaderManager` works. (It's perfectly understandable if some of this stuff doesnt make any sense at all, by the way... you will get more used to it as time goes on.) – Alex Lockwood Jun 22 '12 at 18:15
  • Anyway, have you looked at the [API Demo](http://developer.android.com/reference/android/app/LoaderManager.html)? The list knows how to display the data because (1) you have called `setListAdapter` on your `CursorAdapter` (so it knows to associate any data that is passed to the adapter with the listview). And (2) you swap the cursor into the `CursorAdapter` in `onLoadFinished` (with `mAdapter.swapCursor(data)`). – Alex Lockwood Jun 22 '12 at 18:18
  • Ahh, you are using a custom implementation of `SimpleCursorLoader` because you have not implemented a `ContentProvider`, I assume? – Alex Lockwood Jun 22 '12 at 18:18
  • Have you returned the `new SimpleCursorLoader(...)` in your `onCreateLoader` method? If that doesn't work, you might want to ask a new question on StackOverflow (you should provide code and info about how you have implemented the Loader Callbacks, etc.). I'm not as familiar with working with custom `Loader` implementations and the best I could do is do some guess and check, at least without seeing more of your code. :) – Alex Lockwood Jun 22 '12 at 18:21
  • Unless there is no problem... in which case all is well :) – Alex Lockwood Jun 22 '12 at 18:22
  • So I've fixed (rather, removed all the unnecessary code mentioned above, thanks!) but that wasnt causing the issue, it remains.. The Activity loads, and however so, opens the cursor for the first tab (im guessing because its first?), when I click the second tab, it attempts to use the Cursor from the first tab, which is when the error mentioned in my question appears.. – Rabbott Jun 22 '12 at 20:26
  • Hmm... I think I kind of understand what you are asking, but I'm not confident enough in giving you a solution (especially here as a < 500 character comment) unless you provide more code. You should either update your question entirely or just ask a brand new question all together (I suggest the latter just so you can get all of the attention from the SO community that you need :D). – Alex Lockwood Jun 22 '12 at 21:46
  • 1
    Either way, you should provide more info on what you are trying to achieve, how the fragments relate to one another, what kind of data each displays, etc. It seems like your problem is more of a matter of design rather than a specific problem with how you are handling your cursor. For the most part, Fragments should be independent of one another, so if you are trying to have your fragment directly reuse the cursor of another fragment, you shouldn't do that. Link me to your new question if you make one too... :) – Alex Lockwood Jun 22 '12 at 21:48
  • New question with more deets -- http://stackoverflow.com/questions/11166032/sherlockfragmentactivity-with-multiple-listfragments-and-sqlite-cursor-battles – Rabbott Jun 23 '12 at 01:18