How to use two Cursors and CursorJoiner in LoaderManager in android

android, android-cursorloader, android-loadermanager

Solution

Use two loaders, one for each cursor. When either one finishes loading, call another method that will join them if both have loaded.

// Loader IDs. You could also generate unique R.id values via XML
private static final int LOADER_ID_CURSOR_1 = 1;
private static final int LOADER_ID_CURSOR_2 = 2;

private Cursor cursor1 = null;
private Cursor cursor2 = null;

// return loader for cursor 1
private CusorLoader getCursor1Loader() {
    Uri uri = Uri.parse(abc);
    String[] select = abc; 
    String where = abc;
    String[] whereArgs = abc;
    String sortOrder = abc;
    return new CursorLoader(uri, select, where, whereArgs, sortOrder);
}

// return loader for cursor 2
private CusorLoader getCursor2Loader() {
    // same as above but with different values
    return new CursorLoader(uri, select, where, whereArgs, sortOrder);
}

// to start loading, ...
LoaderManager lm = getLoaderManager();
lm.initLoader(LOADER_ID_CURSOR_1, null, this);
lm.initLoader(LOADER_ID_CURSOR_2, null, this);

// LoaderCallbacks implementations
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    switch(id) {
    case LOADER_ID_CURSOR_1:
        return getCursor1Loader();
    case LOADER_ID_CURSOR_2:
        return getCursor2Loader();
    }
}

@override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    switch(loader.getId()) {
    case LOADER_ID_CURSOR_1:
        cursor1 = data;
        joinCursors();
        break;
    case LOADER_ID_CURSOR_2:
        cursor2 = data;
        joinCursors();
        break;
    }
}

private void joinCursors() {
    if (cursor1 != null && cursor2 != null) {
        // use CursorJoiner here
    }
}

Problem

I have a `ContentProvider`, it's having two tables 1. `OnlineContacts` 2. `AllContacts`. Then i have a method in which i am querying both the tables and getting their resultant `cursors` separately. And then joining them using `CursorJoiner` and making a list of `Contacts`. Passing this list to my `CustomAdapter extending BaseAdapter`, i am populating my `listview`. Like : ``` public static List<Contact> getContacts(Context context){ List<Contact> contactList = new ArrayList<Contact>(); // Getting First Cursor String URL = xyz; Uri baseUri1 = Uri.parse(URL); String[] select = xyz; String where =xyz; Cursor cursor = context.getContentResolver().query(baseUri1, select, where, null, "pid"); // Getting 2nd Cursor Uri baseUri = xyz; String[] projection =xyz; String selection =xyz; String[] selectionArgs = null; String sortOrder = xyz; Cursor mCursor= context.getContentResolver().query(baseUri, projection, selection, selectionArgs, sortOrder); // Joinging Both Cursors CursorJoiner joiner = new CursorJoiner(cursor, new String[] {MyContentProvider.PHONE_ID} , mCursor, new String[] {MyContentProvider.Phone._ID}); for (CursorJoiner.Result joinerResult : joiner) { Contact cont = new Contact(); switch (joinerResult) { case LEFT: // handle case where a row in cursorA is unique break; case RIGHT: // handle case where a row in cursorB is unique case BOTH: // handle case where a row with the same key is in both cursors cont.setID(xyz); cont.setName(xyz); cont.setPhoneNumber(xyz); cont.setStatus("0"); contactList.add(cont); break; } } mCursor.close(); cursor.close(); return contactList; } ``` And here is my CustomAdapter : ``` private class CustomAdapter extends BaseAdapter { List<Contact> contactsList ; public CustomAdapter(List<Contact> contactsList){ this.contactsList = contactsList; } public List<Contact> contacts() { return this.contactsList; } @Override public int getCount() { return contactsList.size(); } @Override public Contact getItem(int arg0) { return contactsList.get(arg0); } @Override public long getItemId(int arg0) { return arg0; } @Override public View getView(int position, View view, ViewGroup viewGroup) { SimpleViewHolder viewHolder; if(view==null) { LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflater.inflate(R.layout.list_item, viewGroup,false); viewHolder = new SimpleViewHolder(view); view.setTag(viewHolder); } viewHolder = (SimpleViewHolder) view.getTag(); TextView contName = (TextView) viewHolder.get(R.id.nameText); ImageView image = (ImageView) viewHolder.get(R.id.contact_image); Contact contact = contactsList.get(position); image.setBackgroundResource(R.drawable.person_empty_offline); contName.setText(contact.getName()); return view; } } ``` Now , i need to do it using `LoaderManager`. I know , to some extent, the implementation of it. I know , the `onCreateLoader` acts like: ``` public Loader<Cursor> onCreateLoader(int id, Bundle args) { Uri baseUri = xyz; String[] projection = xyz; String selection = xyz; String[] selectionArgs = null; String sortOrder = xyz; return new CursorLoader(getActivity(), baseUri, projection, selection, selectionArgs, sortOrder); } ``` And in `OnCreate` , if i use `MyCursorAdapter extending CursorAdapter`, we do something like : ``` mAdapter = new MyCursorAdapter(getActivity(), null, 0); setListAdapter(mAdapter); getLoaderManager().initLoader(0, null, this); ``` Now, i need to do is how can i achive the above implementation using `LoaderManager`. I didn't know how to ask thats why its too explanatory.

Original source