2013-02-04 55 views
9

我正在尝试获取使用联系人的电子邮件ID。为此我使用光标加载器。有一个问题我也收到重复的电子邮件ID。如何删除电子邮件的重复。我应该使用原始查询“SELECT DISTINCT”而不是使用CursorLoader还是有其他解决方案?使用CursorLoader获取电子邮件导致电子邮件重复

@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); 
} 

回答

5

我最近遇到了这个问题。看起来CursorLoader没有实现“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); 
} 

这里是我的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(); 
} 

你应该能够专门修改此为您需要。

+0

谢谢mars,我曾经使用过这种方法。正在寻找其他解决方案,我不需要使用内存。 –

+0

我做了类似的事情,但使用Cursor而不是List。 – zeeshan

0

您可以将setDistinct放入您的内容提供商。

@Override 
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { 
    ... 
    final SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 
    qb.setDistinct(true); 
+0

问题是关于CursorLoader,而不是SQL查询 – Build3r

3

受@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); 
    } 
+0

如果项目不包含DISPLAY_NAME,compareToIgnore会有错误,所以最好在cursorLoader的WHERE子句中指定您不接受任何为空的Name值。 – NVA

0

如果你担心性能,不希望在onLoadFinished()再次玩弄光标,然后有一个小黑客

我合并了以下SO的两个解决方案。

  1. select distinct value in android sqlite

  2. CursorLoader with rawQuery

这里是我工作的解决方案:

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

如果在这种情况下,表名看到的是同样是前2个案件,但我创造了一个虚拟Uri来实现这一点。可能不是一个很好的方法,但完美的作品。

1

我在项目中使用的一个小黑客 - 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); 
} 

此代码只返回包名称和画廊它们的ID。 所以,我想重写代码那样:

@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); 
} 
0

我找到了解决 在选择阵列中使用DISTINCT关键字。

String[] projection = new String[] { ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME, "DISTINCT" + ContactsContract.CommonDataKinds.Email.DATA}; 
相关问题