0

I'm implementing an activity with recyclerview. I load all the contacts that I have in the phone (name and phone numbers). All looks ok, the problem is that when I do a scroll in the view, when I come back at the same contact this contact don't have the correct phone numbers. Is the only one that change. Name and contact phone are display correctly.

For example, one contact only have set Mobile phone. Looks ok when initialize, but if I do scroll and come back, the Home and Work are set with another numbers, and this user only have set Mobile phone

Some help will be apreciate!

This is my onBind method in the recyclerAdapter:

 @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        dataCursor.moveToPosition(position);

            holder.mTextView.setText((dataCursor.getString(1)));

            ContentResolver cr = context.getContentResolver();
            String contactId = dataCursor.getString(dataCursor.getColumnIndex(ContactsContract.Contacts._ID));

            Long photoTest = dataCursor.getLong(dataCursor.getColumnIndex(ContactsContract.Contacts.PHOTO_ID));

            if (dataCursor.moveToFirst()) {
                Cursor phones = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + contactId, null, null);

                if (phones == null) {
                    phones.close();
                } else {

                    while (phones.moveToNext()) {
                        try {
                            Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?", new String[]{contactId}, null);
                            while (pCur.moveToNext()) {
                                int phoneType = pCur.getInt(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE));
                                String phoneNumber = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));

                                if(phoneType == TYPE_MOBILE){
                                    holder.mNumberMoBilePhone.setText(phoneNumber);
                                    holder.mNumberMoBilePhone.setVisibility(View.VISIBLE);
                                    holder.textMobilePhone.setVisibility(View.VISIBLE);
                                }else if(phoneType == TYPE_HOME){
                                    holder.mNumberHomePhone.setText(phoneNumber);
                                    holder.mNumberHomePhone.setVisibility(View.VISIBLE);
                                    holder.textHomePhone.setVisibility(View.VISIBLE);
                                }else if(phoneType == TYPE_WORK){
                                    holder.mNumberWorkPhone.setText(phoneNumber);
                                    holder.mNumberWorkPhone.setVisibility(View.VISIBLE);
                                    holder.textWorkPhone.setVisibility(View.VISIBLE);
                                }else{}

                            }
                        } catch (NullPointerException n) {

                        }
                    }
                    phones.close();
                }
            }

            if (photoTest != null) {
                ContactPhotoLoaderSdk5.instance().loadPhoto(holder.mContactPhoto, photoTest);
            }

    }

Not sure if have to be something with thit, but this is my select:

String select = "((" + ContactsContract.Contacts.DISPLAY_NAME + " NOTNULL) AND (" + ContactsContract.Contacts.HAS_PHONE_NUMBER + " != 0 ))";
S.P.
  • 2,274
  • 4
  • 26
  • 57
  • I would recommend getting all your data from the database when setting up the adapter. Put this data into a list and use the list in the adapter. This will improve performance, make your code much cleaner and your mistake easier to spot. – Robbe Aug 16 '16 at 16:37

2 Answers2

1

This happens because of the way RecyclerView works, and has nothing to do with the way you are accessing the contact data. A RecyclerView only creates a ViewHolder for each of the views that will fit on screen at one time, then recycles those views when they are scrolled off screen. Then the new content for that view gets applied in onBindViewHolder().

Since you may have assigned text for the ViewHolder.textHomePhone and ViewHolder.textWorkPhone text views previously, when those view holders get recycled that text is still there. Therefore, if the new contact only has a mobile number, the text for the home number and work number will still be filled out by the previous contact occupying that ViewHolder.

To fix this you need to check if the contact doesn't have a number of each type (mobile, home and work), and if so set the visibility of the corresponding TextView to View.GONE.

A simple way to do this would be to create three boolean values before your loop, then check them afterwards:

boolean hasMobile = false;
boolean hasHome = false;
boolean hasWork = false;

while (pCur.moveToNext()) {
    int phoneType = pCur.getInt(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE));
    String phoneNumber = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));

    if(phoneType == TYPE_MOBILE){
        holder.mNumberMoBilePhone.setText(phoneNumber);
        holder.mNumberMoBilePhone.setVisibility(View.VISIBLE);
        holder.textMobilePhone.setVisibility(View.VISIBLE);
        hasMobile = true;
    }else if(phoneType == TYPE_HOME){
        holder.mNumberHomePhone.setText(phoneNumber);
        holder.mNumberHomePhone.setVisibility(View.VISIBLE);
        holder.textHomePhone.setVisibility(View.VISIBLE);
        hasHome = true;
    }else if(phoneType == TYPE_WORK){
        holder.mNumberWorkPhone.setText(phoneNumber);
        holder.mNumberWorkPhone.setVisibility(View.VISIBLE);
        holder.textWorkPhone.setVisibility(View.VISIBLE);
        hasWork = true;
    }
}

if(!hasMobile) {
    holder.mNumberMobilePhone.setVisibility(View.GONE);
    holder.textMobilePhone.setVisibility(View.GONE);
}

if(!hasHome) {
    holder.mNumberHomePhone.setVisibility(View.GONE);
    holder.textHomePhone.setVisibility(View.GONE);
}

if(!hasWork) {
    holder.mNumberWorkPhone.setVisibility(View.GONE);
    holder.textWorkPhone.setVisibility(View.GONE);
}
Bryan
  • 14,756
  • 10
  • 70
  • 125
0

I think the problem is with the following line:

if (dataCursor.moveToFirst())

you move the data cursor to point to the first element in each call which is not necessary and this will undo the following line at the top of the function:

dataCursor.moveToPosition(position);

if you remove the if statement, it should work fine

Pooya
  • 6,083
  • 3
  • 23
  • 43
  • Hi @pooya Still having same problem with your solution – S.P. Aug 16 '16 at 16:39
  • @D.O. it is quite hard to debug from here but there are also some semantics problem in your code for example while (phones.moveToNext()) needs to have phones.moveToFirst() before that. Please see if you can correct those first to help get more reliable output – Pooya Aug 16 '16 at 17:06
  • This is the implementation that I'm trying to do in my code to read all the phone numberes. Maybe this can help you to give me some solucion. Is the answer of @anivaler http://stackoverflow.com/questions/2356084/read-all-contacts-phone-numbers-in-android – S.P. Aug 16 '16 at 18:32
  • @D.O. in RecyclerView what you should do is to just update the data on each row when the user scrolls and the data becomes invalidated so you can't read everything in onBindViewHolder – Pooya Aug 16 '16 at 18:36