2013-02-04 36 views
9

Tôi đang cố gắng nhận các id email sử dụng danh bạ. Cho rằng tôi đang sử dụng Cursor Loader. Có một vấn đề tôi đang nhận được id email trùng lặp cũng có. Cách xóa trùng lặp email. Tôi có nên sử dụng truy vấn thô "SELECT DISTINCT" thay vì sử dụng CursorLoader hoặc có một số giải pháp khác không?Sử dụng CursorLoader để nhận email làm sao chép email

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

Trả lời

5

Gần đây, tôi đã gặp sự cố này. Dường như CursorLoader không có triển khai "DISTINCT". Cách giải quyết của tôi cho biết thêm một vài dòng với phương pháp onLoadFinish và mở rộng BaseAdapter để chấp nhận một tham số liệt kê:

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

Đây là lớp BaseAdapter tôi:

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

Bạn sẽ có thể sửa đổi này đặc biệt dành cho bạn nhu cầu.

+0

Cảm ơn mars, tôi đã sử dụng phương pháp tiếp cận này. Đã tìm kiếm một số giải pháp khác mà tôi sẽ không phải sử dụng bộ nhớ. –

+0

Tôi đã làm một cái gì đó tương tự nhưng được sử dụng Con trỏ thay vì Danh sách. – zeeshan

0

Bạn có thể đặt setDistinct trong nhà cung cấp nội dung của mình.

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

Câu hỏi liên quan đến CursorLoader, chứ không phải truy vấn SQL – Build3r

3

Lấy cảm hứng từ @mars, tôi có giải pháp không cần sửa đổi bộ điều hợp. Ý tưởng là xóa các bản sao của con trỏ; vì không có cách nào để làm điều đó, chúng tôi tạo ra một con trỏ mới mà không có các bản sao.

Tất cả các mã trong 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

Nếu mục không chứa một compareToIgnore DISPLAY_NAME sẽ có lỗi do đó bạn nên chỉ rõ trong mệnh đề WHERE của cursorLoader mà bạn không chấp nhận bất kỳ giá trị Tên nào là rỗng. – NVA

0

Nếu bạn đang lo lắng về hiệu suất và không muốn chơi xung quanh với con trỏ một lần nữa trong onLoadFinished(), sau đó là một hack nhỏ

Tôi kết hợp sau hai giải pháp từ SO.

  1. select distinct value in android sqlite

  2. CursorLoader with rawQuery

Và đây là giải pháp làm việc của tôi:

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

Nếu bạn thấy tên trường hợp Bảng điều này là cùng là lần đầu tiên 2 trường hợp, nhưng tôi tạo ra một Uri giả để đạt được điều này. Có thể không phải là một cách tiếp cận rất tốt nhưng hoạt động hoàn hảo.

1

tôi đã sử dụng một hack nhỏ trong dự án của tôi - một SQL injection, như thế:

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

Mã này chỉ trả về tên bó và ID của họ từ Gallery. Vì vậy, tôi muốn viết lại mã của bạn như thế:

@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

Tôi tìm thấy một giải pháp Sử dụng DISTINCT từ khóa trong việc lựa chọn Array.

String[] projection = new String[] { ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME, "DISTINCT" + ContactsContract.CommonDataKinds.Email.DATA}; 
Các vấn đề liên quan