Android 使用CursorLoader获取电子邮件会导致电子邮件重复
我正在尝试获取联系人的电子邮件ID。为此,我使用游标加载器。有一个问题,我得到重复的电子邮件ID也。如何消除电子邮件的重复性。我应该使用原始查询“SELECTDISTINCT”而不是使用CursorLoader还是有其他解决方案Android 使用CursorLoader获取电子邮件会导致电子邮件重复,android,android-contacts,android-cursorloader,Android,Android Contacts,Android Cursorloader,我正在尝试获取联系人的电子邮件ID。为此,我使用游标加载器。有一个问题,我得到重复的电子邮件ID也。如何消除电子邮件的重复性。我应该使用原始查询“SELECTDISTINCT”而不是使用CursorLoader还是有其他解决方案 @Override public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) { String[] projection = new String[] { ContactsContract
@Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
String[] projection = new String[] { ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.CommonDataKinds.Email.DATA};
String sortOrder = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
String selection = ContactsContract.Contacts.IN_VISIBLE_GROUP +"='1' AND " + Email.DATA +" IS NOT NULL AND " + Email.DATA +" != \"\" " ;
//showing only visible contacts
String[] selectionArgs = null;
return new CursorLoader(this, ContactsContract.CommonDataKinds.Email.CONTENT_URI, projection, selection, selectionArgs, sortOrder);
}
@覆盖
公共加载器onCreateLoader(int arg0,Bundle arg1){
字符串[]投影=新字符串[]{ContactsContract.Contacts.\u ID,ContactsContract.Contacts.DISPLAY\u NAME,ContactsContract.CommonDataTypes.Email.DATA};
字符串排序器=Contacts contract.Contacts.DISPLAY_NAME+“整理本地化ASC”;
字符串选择=Contacts contract.Contacts.IN_VISIBLE_GROUP+“='1'和“+Email.DATA+”不为空且“+Email.DATA+”!=\”;
//只显示可见的联系人
字符串[]selectionArgs=null;
返回新的游标装入器(此,ContactsContract.CommonDataTypes.Email.CONTENT\u URI,投影,选择,SelectionAgs,sortOrder);
}
我最近遇到了这个问题。游标加载程序似乎没有“DISTINCT”的实现。我的解决方法是向onLoadFinish方法添加几行代码,并扩展BaseAdapter以接受列表参数:
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String projection[] = {
CommonDataKinds.Phone._ID,
CommonDataKinds.Phone.DISPLAY_NAME,
};
String select = "((" + CommonDataKinds.Phone.DISPLAY_NAME + " NOTNULL) and " + CommonDataKinds.Phone.HAS_PHONE_NUMBER + " > 0)";
String sort = CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
CursorLoader loader = new CursorLoader(
mContext,
CommonDataKinds.Phone.CONTENT_URI,
projection,
select,
null,
sort
);
return loader;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
List<String> displayNames = new ArrayList<String>();
cursor.moveToFirst();
while(!cursor.isAfterLast()){
String name = cursor.getString(cursor.getColumnIndex(CommonDataKinds.Phone.DISPLAY_NAME));
if(!displayNames.contains(name))
displayNames.add(name);
cursor.moveToNext();
}
mAdapter.swapCursor(displayNames);
}
@覆盖
公共加载器onCreateLoader(int-id,Bundle-args){
字符串投影[]={
CommonDataTypes.Phone.\u ID,
CommonDataTypes.Phone.DISPLAY\u名称,
};
String select=“((“+CommonDataTypes.Phone.DISPLAY_NAME+”NOTNULL)和“+CommonDataTypes.Phone.HAS_Phone_NUMBER+”>0)”;
字符串排序=CommonDataTypes.Phone.DISPLAY_NAME+“ASC”;
游标装入器装入器=新游标装入器(
McContext,
CommonDataTypes.Phone.CONTENT\u URI,
投影,
选择,
无效的
分类
);
返回装载机;
}
@凌驾
public void onLoadFinished(加载器,光标){
List displayNames=new ArrayList();
cursor.moveToFirst();
而(!cursor.isAfterLast()){
字符串名称=cursor.getString(cursor.getColumnIndex(commonDataTypes.Phone.DISPLAY_name));
如果(!displayNames.contains(name))
displayNames.add(名称);
cursor.moveToNext();
}
mAdapter.swapCursor(显示名称);
}
下面是我的BaseAdapter类:
public class AdapterAddContacts extends BaseAdapter{
private List<String> mData = new ArrayList<String>();
private Context mContext;
public AdapterAddContacts(Context context,List<String> displayNames){
mData = displayNames;
mContext = context;
}
@Override
public int getCount() {
if(mData != null)
return mData.size();
else
return 0;
}
@Override
public Object getItem(int pos) {
return mData.get(pos);
}
@Override
public long getItemId(int id) {
return id;
}
@Override
public View getView(int pos, View convertView, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(R.layout.entry_add_contacts,parent,false);
String data = mData.get(pos);
TextView textName = (TextView)view.findViewById(R.id.my_contacts_add_display_name);
textName.setText(data);
textName.setTag(data);
return view;
}
public void swapCursor(List<String> displayNames){
mData = displayNames;
this.notifyDataSetChanged();
}
公共类适配器AddContacts扩展BaseAdapter{
private List mData=new ArrayList();
私有上下文;
公共适配器地址联系人(上下文、列表显示名称){
mData=显示名称;
mContext=上下文;
}
@凌驾
public int getCount(){
如果(mData!=null)
返回mData.size();
其他的
返回0;
}
@凌驾
公共对象getItem(int-pos){
返回mData.get(pos);
}
@凌驾
公共长getItemId(int id){
返回id;
}
@凌驾
公共视图getView(int pos、视图转换视图、视图组父视图){
LayoutFlater充气机=LayoutFlater.from(mContext);
视图=充气机。充气(右布局。输入\添加\联系人,父项,错误);
字符串数据=mData.get(pos);
TextView textName=(TextView)view.findViewById(R.id.my\u contacts\u add\u display\u name);
textName.setText(数据);
textName.setTag(数据);
返回视图;
}
公共无效交换(列表显示名称){
mData=显示名称;
this.notifyDataSetChanged();
}
您应该能够根据自己的需要对其进行专门的修改。您可以在内容提供商中输入内容
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
...
final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setDistinct(true);
受@mars的启发,我有了一个不需要修改适配器的解决方案。想法是删除光标的重复项;因为没有办法,我们创建了一个没有重复项的新光标 所有代码都在
onLoadFinished
中:
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
MatrixCursor newCursor = new MatrixCursor(PROJECTION); // Same projection used in loader
if (cursor.moveToFirst()) {
String lastName = "";
do {
if (cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)).compareToIgnoreCase(lastName) != 0) {
newCursor.addRow(new Object[]{cursor.getString(0), cursor.getString(1), cursor.getString(2) ...}); // match the original cursor fields
lastName =cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
}
} while (cursor.moveToNext());
}
mContactsAdapter.swapCursor(newCursor);
}
@覆盖
public void onLoadFinished(加载器,光标){
MatrixCursor newCursor=新MatrixCursor(投影);//与loader中使用的投影相同
if(cursor.moveToFirst()){
字符串lastName=“”;
做{
if(cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataTypes.Phone.DISPLAY_NAME)).CompareTIgnoreCase(lastName)!=0){
newCursor.addRow(新对象[]{cursor.getString(0)、cursor.getString(1)、cursor.getString(2)…});//匹配原始的游标字段
lastName=cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataTypes.Phone.DISPLAY_NAME));
}
}while(cursor.moveToNext());
}
mContactsAdapter.swapCursor(newCursor);
}
如果您担心性能,不想在onLoadFinished()中再次使用游标,那么有一个小问题
我结合了来自SO的以下两种解决方案
以下是我的工作解决方案:
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
String tableName;
/*
* Choose the table to query and a sort order based on the code returned
* for the incoming URI.
*/
switch (uriMatcher.match(uri)) {
case NOTIFICATION:
tableName = NOTIFICATIONS_TABLE_NAME;
break;
case NOTIFICATION_TIMESTAMP:
Cursor cursor = db.query(true, NOTIFICATIONS_TABLE_NAME, projection, selection, selectionArgs, TIMESTAMP, null, sortOrder, null);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
case DOWNLOAD:
tableName = DOWNLOADS_TABLE;
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
if (selection != null) {
selection = selection + "=?";
}
Cursor cursor = db.query(tableName, projection, selection, selectionArgs, null, null, sortOrder);
// Tell the cursor what uri to watch, so it knows when its source data
// changes
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
如果您在本例中看到,表名相同是前两种情况,但我创建了一个虚拟Uri来实现这一点。这可能不是一个很好的方法,但效果很好。我在我的项目中使用了一个小技巧-SQL注入,如下所示:
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new CursorLoader(
this,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new String[] {
"DISTINCT "+ MediaStore.Images.Media.BUCKET_ID,
MediaStore.Images.Media.BUCKET_DISPLAY_NAME},
null, null, null);
}
@Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
String[] projection = new String[] {
"DISTINCT " + ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Email.DATA};
String sortOrder = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
String selection = ContactsContract.Contacts.IN_VISIBLE_GROUP +"='1' AND " + Email.DATA +" IS NOT NULL AND " + Email.DATA +" != \"\" " ;
//showing only visible contacts
String[] selectionArgs = null;
return new CursorLoader(this, ContactsContract.CommonDataKinds.Email.CONTENT_URI, projection, selection, selectionArgs, sortOrder);
}
@覆盖
公共加载器onCreateLoader(int-id,Bundle-args){
返回新游标装入器(
这
MediaStore.Images.Media.EXTERNAL\u CONTENT\u URI,
新字符串[]{
“独特”+MediaStore.Images.Media.BUCKET_ID,
MediaStore.Images.Media.BUCKET\u DISPLAY\u NAME},
空,空,空);
}
此代码仅从Gallery返回捆绑包名称及其ID。
所以,我会像这样重写你的代码:
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new CursorLoader(
this,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new String[] {
"DISTINCT "+ MediaStore.Images.Media.BUCKET_ID,
MediaStore.Images.Media.BUCKET_DISPLAY_NAME},
null, null, null);
}
@Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
String[] projection = new String[] {
"DISTINCT " + ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Email.DATA};
String sortOrder = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
String selection = ContactsContract.Contacts.IN_VISIBLE_GROUP +"='1' AND " + Email.DATA +" IS NOT NULL AND " + Email.DATA +" != \"\" " ;
//showing only visible contacts
String[] selectionArgs = null;
return new CursorLoader(this, ContactsContract.CommonDataKinds.Email.CONTENT_URI, projection, selection, selectionArgs, sortOrder);
}
@覆盖
公共加载器onCreateLoader(int arg0,Bundle arg1){
字符串[]投影=新字符串[]{
“不同”+联系人合同联系人。\u ID,
Contacts contract.Contacts.DISPLAY\u NAME,
ContactsContract.CommonDataTypes.Email.DATA};
字符串排序器=Contacts contract.Contacts.DISPLAY_NAME+“整理本地化ASC”;
字符串选择=Contacts contract.Contacts.IN_VI