Monday, May 21, 2012

[android-developers] SimpleCursorTreeAdapter and CursorLoader for ExpandableListView

I am trying to asynchronously query a provider by using a CursorLoader with a SimpleCursorTreeAdapter

Here is my Fragment class which implements the CursorLoader

public class GroupsListFragment extends ExpandableListFragment implements
 
LoaderManager.LoaderCallbacks<Cursor> {

 
private final String DEBUG_TAG = getClass().getSimpleName().toString();      

 
private static final String[] CONTACTS_PROJECTION = new String[] {
   
ContactsContract.Contacts._ID,
   
ContactsContract.Contacts.DISPLAY_NAME };

 
private static final String[] GROUPS_SUMMARY_PROJECTION = new String[] {
   
ContactsContract.Groups.TITLE, ContactsContract.Groups._ID,
   
ContactsContract.Groups.SUMMARY_COUNT,
   
ContactsContract.Groups.ACCOUNT_NAME,
   
ContactsContract.Groups.ACCOUNT_TYPE,
   
ContactsContract.Groups.DATA_SET };

 
GroupsAdapter mAdapter;

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

    populateContactList
();

    getLoaderManager
().initLoader(-1, null, this);
 
}

 
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
   
// This is called when a new Loader needs to be created.
   
Log.d(DEBUG_TAG, "onCreateLoader for loader_id " + id);
   
CursorLoader cl;
   
if (id != -1) {
     
// child cursor
     
Uri contactsUri = ContactsContract.Data.CONTENT_URI;
     
String selection = "(("
       
+ ContactsContract.CommonDataKinds.GroupMembership.DISPLAY_NAME
       
+ " NOTNULL) AND ("
       
+ ContactsContract.CommonDataKinds.GroupMembership.HAS_PHONE_NUMBER
       
+ "=1) AND ("
       
+ ContactsContract.CommonDataKinds.GroupMembership.DISPLAY_NAME
       
+ " != '') AND ("
       
+ ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID
       
+ " = ? ))";
     
String sortOrder = ContactsContract.CommonDataKinds.GroupMembership.DISPLAY_NAME
       
+ " COLLATE LOCALIZED ASC";
     
String[] selectionArgs = new String[] { String.valueOf(id) };

      cl
= new CursorLoader(getActivity(), contactsUri,
        CONTACTS_PROJECTION
, selection, selectionArgs, sortOrder);
   
} else {
     
// group cursor
     
Uri groupsUri = ContactsContract.Groups.CONTENT_SUMMARY_URI;
     
String selection = "((" + ContactsContract.Groups.TITLE
       
+ " NOTNULL) AND (" + ContactsContract.Groups.TITLE
       
+ " != '' ))";
     
String sortOrder = ContactsContract.Groups.TITLE
       
+ " COLLATE LOCALIZED ASC";
      cl
= new CursorLoader(getActivity(), groupsUri,
        GROUPS_SUMMARY_PROJECTION
, selection, null, sortOrder);
   
}

   
return cl;
 
}

 
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
   
// Swap the new cursor in.
   
int id = loader.getId();
   
Log.d(DEBUG_TAG, "onLoadFinished() for loader_id " + id);
   
if (id != -1) {
     
// child cursor
     
if (!data.isClosed()) {
       
Log.d(DEBUG_TAG, "data.getCount() " + data.getCount());
       
try {
          mAdapter
.setChildrenCursor(id, data);
       
} catch (NullPointerException e) {
         
Log.w("DEBUG","Adapter expired, try again on the next query: "
           
+ e.getMessage());
       
}
     
}
   
} else {
      mAdapter
.setGroupCursor(data);
   
}

 
}

 
public void onLoaderReset(Loader<Cursor> loader) {
   
// This is called when the last Cursor provided to onLoadFinished()
   
// is about to be closed.
   
int id = loader.getId();
   
Log.d(DEBUG_TAG, "onLoaderReset() for loader_id " + id);
   
if (id != -1) {
     
// child cursor
     
try {
        mAdapter
.setChildrenCursor(id, null);
     
} catch (NullPointerException e) {
       
Log.w("TAG", "Adapter expired, try again on the next query: "
         
+ e.getMessage());
     
}
   
} else {
      mAdapter
.setGroupCursor(null);
   
}
 
}

 
/**
  * Populate the contact list
  */

 
private void populateContactList() {
   
// Set up our adapter
    mAdapter
= new GroupsAdapter(getActivity(),this,
      android
.R.layout.simple_expandable_list_item_1,
      android
.R.layout.simple_expandable_list_item_1,
     
new String[] { ContactsContract.Groups.TITLE }, // Name for group layouts
     
new int[] { android.R.id.text1 },
     
new String[] { ContactsContract.Contacts.DISPLAY_NAME }, // Name for child layouts
     
new int[] { android.R.id.text1 });

    setListAdapter
(mAdapter);
 
}
}

And here is my adapter which subclasses SimpleCursorTreeAdapter

public class GroupsAdapter extends SimpleCursorTreeAdapter {

 
private final String DEBUG_TAG = getClass().getSimpleName().toString();

 
private ContactManager mActivity;
 
private GroupsListFragment mFragment;

 
// Note that the constructor does not take a Cursor. This is done to avoid
 
// querying the database on the main thread.
 
public GroupsAdapter(Context context, GroupsListFragment glf,
   
int groupLayout, int childLayout, String[] groupFrom,
   
int[] groupTo, String[] childrenFrom, int[] childrenTo) {

   
super(context, null, groupLayout, groupFrom, groupTo, childLayout,
      childrenFrom
, childrenTo);
    mActivity
= (ContactManager) context;
    mFragment
= glf;
 
}

 
@Override
 
protected Cursor getChildrenCursor(Cursor groupCursor) {
   
// Given the group, we return a cursor for all the children within that group
   
int groupId = groupCursor.getInt(groupCursor
     
.getColumnIndex(ContactsContract.Groups._ID));

   
Log.d(DEBUG_TAG, "getChildrenCursor() for groupId " + groupId);

   
Loader loader = mActivity.getLoaderManager().getLoader(groupId);
   
if ( loader != null && loader.isReset() ) {
      mActivity
.getLoaderManager().restartLoader(groupId, null, mFragment);
   
} else {
      mActivity
.getLoaderManager().initLoader(groupId, null, mFragment);
   
}

 
}

}

The problem is that when i click one of the parent groups one of three things happens in what appears to be a inconsistent fashion.

1) Either the group opens up and the children appear below it

2) The group does not open and the setChildrenCursor() call throws an NullPointerException error which gets caught in the try catch block

3) The group does not open and no error is thrown

Here is some debugging output in a scenario in which a group is expanded and showing the children:

When all groups are displayed it ouputs:

05-20 10:08:22.765: D/GroupsListFragment(22132): onCreateLoader for loader_id -1
05-20 10:08:23.613: D/GroupsListFragment(22132): onLoadFinished() for loader_id -1

-1 is the loader_id of the group cursor

Then if i select one group in particular (let's just call it group A) it outputs:

05-20 23:22:31.140: D/GroupsAdapter(13844): getChildrenCursor() for groupId 67
05-20 23:22:31.140: D/GroupsListFragment(13844): onCreateLoader for loader_id 67
05-20 23:22:31.254: D/GroupsListFragment(13844): onLoadFinished() for loader_id 67
05-20 23:22:31.254: D/GroupsListFragment(13844): data.getCount() 4
05-20 23:22:31.254: W/GroupsListFragment(13844): Adapter expired, try again on the next query: null

The group does not expand and the Null Pointer Exception is caught. Then if i select another group (let's just call it group B) it outputs:

05-20 23:25:38.089: D/GroupsAdapter(13844): getChildrenCursor() for groupId 3
05-20 23:25:38.089: D/GroupsListFragment(13844): onCreateLoader for loader_id 3
05-20 23:25:38.207: D/GroupsListFragment(13844): onLoadFinished() for loader_id 3
05-20 23:25:38.207: D/GroupsListFragment(13844): data.getCount() 6

This time, the Null Pointer Exception is not thrown. And instead of group B expanding, group A is expanded.

Can anyone explain the behavior that the setChildrenCursor() call is exhibiting?

http://stackoverflow.com/questions/10611927/simplecursortreeadapter-and-cursorloader-for-expandablelistview

--
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to android-developers@googlegroups.com
To unsubscribe from this group, send email to
android-developers+unsubscribe@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home


Real Estate