如何在android的LoaderManager中使用两个Cursor和CursorJoiner
Posted
技术标签:
【中文标题】如何在android的LoaderManager中使用两个Cursor和CursorJoiner【英文标题】:How to use two Cursors and CursorJoiner in LoaderManager in android 【发布时间】:2014-09-04 04:29:32 【问题描述】:我有一个 ContentProvider
,它有两个表 1. OnlineContacts
2. AllContacts
。然后我有一个方法,我在其中查询两个表并分别获取它们的结果cursors
。然后使用 CursorJoiner
加入他们并列出 Contacts
。将此列表传递给我的 CustomAdapter extending BaseAdapter
,我正在填充我的 listview
。喜欢:
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;
这是我的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;
现在,我需要使用 LoaderManager
来完成。我知道,在某种程度上,它的执行。我知道,onCreateLoader
的行为类似于:
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);
在 OnCreate
中,如果我使用 MyCursorAdapter extending CursorAdapter
,我们会执行以下操作:
mAdapter = new MyCursorAdapter(getActivity(), null, 0);
setListAdapter(mAdapter);
getLoaderManager().initLoader(0, null, this);
现在,我需要做的是如何使用 LoaderManager
实现上述实现。我不知道怎么问这就是为什么它太解释了。
【问题讨论】:
您可以使用两个加载器进行两个不同的查询,然后将结果连接起来(检查此gist.github.com/luksprog/7ec8cd3fcdea97b5839c),或者您在ContentProvider
级别实现连接并返回MatrixCursor
from连接的结果。
【参考方案1】:
使用两个加载器,每个游标一个。当任何一个完成加载时,调用另一个方法,如果两者都已加载,将加入它们。
// 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
【讨论】:
Thnx alot @KaraKuri,你的回答正是我想要的。我在对我有用的joinCursor
方法中使用了 1MatrixCursor`。
你好@KaraKuri,你可以看看***.com/questions/25196894/…【参考方案2】:
我编写了一个类,它使用LoaderManager
加载两个不同的Cursors
并返回CursorJoiner.Result
对象,以便您可以处理连接。这段代码没什么好说的,如果有什么不清楚或者有什么问题可以在cmets中提问!
public class JoinLoader
public interface JoinHandler
public void onHandleJoin(CursorJoiner.Result result);
private static final int LOADER_ONE = 0;
private static final int LOADER_TWO = 1;
private final LoaderCallbackImpl callbackOne;
private final LoaderCallbackImpl callbackTwo;
private final Context context;
private final LoaderManager loaderManager;
private Cursor cursorOne;
private Cursor cursorTwo;
private String[] leftColumns;
private String[] rightColumns;
private JoinHandler joinHandler;
private JoinLoader(Activity activity)
this.context = activity;
this.loaderManager = activity.getLoaderManager();
this.callbackOne = new LoaderCallbackImpl(activity, new LoaderCallbackImpl.FinishedListener()
@Override
public void onFinished(Cursor data)
cursorOne = data;
handleSuccess();
);
this.callbackTwo = new LoaderCallbackImpl(activity, new LoaderCallbackImpl.FinishedListener()
@Override
public void onFinished(Cursor data)
cursorTwo = data;
handleSuccess();
);
public void start()
this.cursorOne = null;
this.cursorTwo = null;
this.loaderManager.initLoader(LOADER_ONE, null, this.callbackOne);
this.loaderManager.initLoader(LOADER_TWO, null, this.callbackTwo);
public void setJoinOn(String[] leftColumns, String[] rightColumns)
this.leftColumns = leftColumns;
this.rightColumns = rightColumns;
private void handleSuccess()
if(this.joinHandler != null && this.cursorOne != null && this.cursorTwo != null)
CursorJoiner joiner = new CursorJoiner(this.cursorOne, this.leftColumns, this.cursorTwo, this.rightColumns);
for (CursorJoiner.Result result : joiner)
this.joinHandler.onHandleJoin(result);
this.cursorOne.close();
this.cursorTwo.close();
public void setJoinHandler(JoinHandler joinHandler)
this.joinHandler = joinHandler;
public void setFirstQuery(Uri uri, String[] projection, String selection, String[] selectionArgs, String orderBy)
this.callbackOne.setQuery(uri, projection, selection, selectionArgs, orderBy);
public void setSecondQuery(Uri uri, String[] projection, String selection, String[] selectionArgs, String orderBy)
this.callbackTwo.setQuery(uri, projection, selection, selectionArgs, orderBy);
private static class LoaderCallbackImpl implements LoaderManager.LoaderCallbacks<Cursor>
public interface FinishedListener
public void onFinished(Cursor data);
private final Context context;
private final FinishedListener finishedListener;
private Uri uri;
private String[] projection;
private String selection;
private String[] selectionArgs;
private String orderBy;
private boolean finished = false;
private LoaderCallbackImpl(Context context, FinishedListener listener)
this.context = context;
this.finishedListener = listener;
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args)
this.finished = false;
return new CursorLoader(context, uri, projection, selection, selectionArgs, orderBy);
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data)
this.finished = true;
if(this.finishedListener != null)
this.finishedListener.onFinished(data);
@Override
public void onLoaderReset(Loader<Cursor> loader)
public void setQuery(Uri uri, String[] projection, String selection, String[] selectionArgs, String orderBy)
this.uri = uri;
this.projection = projection;
this.selection = selection;
this.selectionArgs = selectionArgs;
this.orderBy = orderBy;
public boolean isFinished()
return finished;
我测试了这个类,它似乎按预期工作。你可以这样使用它:
JoinLoader loader = new JoinLoader(activity);
loader.setFirstQuery(firstUri, firstProjection, firstSelection, firstSelectionArgs, firstOrderBy);
loader.setSecondQuery(secondUri, secondProjection, secondSelection, secondSelectionArgs, secondOrderBy);
loader.setJoinOn(leftColumns, rightColumns);
loader.setJoinHandler(new JoinLoader.JoinHandler()
@Override
public void onHandleJoin(CursorJoiner.Result result)
switch (result)
case LEFT:
...
break;
case RIGHT:
...
break;
case BOTH:
...
break;
);
loader.start();
希望能帮到你,如果还有什么问题欢迎追问!
【讨论】:
Thnx @Xaver Kapeller 兄弟,我实现了 Karakuri 给出的上述答案,这对我来说更容易理解......现在我尝试用你的方式来查看哪个行为有效。非常感谢。我肯定会问你很多关于很多事情的问题。你很棒。 你好@Xaver Kapeller,你可以看看***.com/questions/25196894/… @Xaver Kapeller 是否可以为左连接和右连接加入光标?以上是关于如何在android的LoaderManager中使用两个Cursor和CursorJoiner的主要内容,如果未能解决你的问题,请参考以下文章
Android 兼容包和 getLoaderManager()