2013-02-04 54 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}; 
相關問題