Search code examples
androidandroid-cursorloaderandroid-loadermanager

How to use two Cursors and CursorJoiner in LoaderManager in android


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.


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
        }
    }