Using CursorLoader to get emails causes duplication of emails

前端 未结 6 2194
攒了一身酷
攒了一身酷 2021-02-14 06:44

I am trying to get email ids of uses contacts. For that I am using Cursor Loader. There is one problem I am getting duplicate email ids also. How to remove email duplicacy. Shou

相关标签:
6条回答
  • 2021-02-14 07:21

    Inspired by @mars, I have a solution that does not need a modification of the adapter. The idea is to delete the duplicates of the cursor; as there is no way to do it, we create a new cursor whithout the duplicates.

    All the code is in 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 讨论(0)
  • 2021-02-14 07:34

    If you are worried about performance and don't want to play around with cursor again in onLoadFinished(), then there is a small hack

    I combined following two solutions from SO.

    1. select distinct value in android sqlite

    2. CursorLoader with rawQuery

    And here is my working solution:

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

    If you see in this case Table name is same is first 2 cases but i created a dummy Uri to achieve this. May not be a very good approach but works perfectly.

    0 讨论(0)
  • 2021-02-14 07:35

    I recently ran into this problem. It appears that the CursorLoader does not have an implementation of "DISTINCT". My workaround adds a few lines to the onLoadFinish method and extends the BaseAdapter to accept a List parameter:

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

    Here is my BaseAdapter class:

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

    You should be able to modify this specifically for your needs.

    0 讨论(0)
  • 2021-02-14 07:35

    I used a small hack in my project - an SQL injection, like that:

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

    This code returns only bundle names and their IDs from Gallery. So, I'd rewrite your code like that:

    @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 讨论(0)
  • 2021-02-14 07:37

    I found a solution Use DISTINCT keyword in selection Array.

    String[] projection = new String[] { ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME, "DISTINCT" + ContactsContract.CommonDataKinds.Email.DATA};
    
    0 讨论(0)
  • 2021-02-14 07:41

    You can put setDistinct in your content provider.

        @Override 
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        ...
        final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
        qb.setDistinct(true);
    
    0 讨论(0)
提交回复
热议问题