滚动视图时,Recyclerview 在contactsContract 中更改我的phoneNumber 的值

Posted

技术标签:

【中文标题】滚动视图时,Recyclerview 在contactsContract 中更改我的phoneNumber 的值【英文标题】:Recyclerview change the value of my phoneNumber in contactsContract when scroll the view 【发布时间】:2016-12-23 01:35:15 【问题描述】:

我正在使用 recyclerview 实施一项活动。我加载了手机中的所有联系人(姓名和电话号码)。一切看起来都很好,问题是当我在视图中滚动时,当我回到同一个联系人时,这个联系人没有正确的电话号码。是唯一一个改变的。姓名和联系电话显示正确。

例如,一个联系人只设置了手机。初始化时看起来没问题,但如果我滚动并返回,家庭和工作设置了另一个数字,并且这个用户只设置了手机

一些帮助将不胜感激!

这是我在 recyclerAdapter 中的 onBind 方法:

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

    

不确定是否必须与此相关,但这是我的选择:

String select = "((" + ContactsContract.Contacts.DISPLAY_NAME + " NOTNULL) AND (" + ContactsContract.Contacts.HAS_PHONE_NUMBER + " != 0 ))";

【问题讨论】:

我建议在设置适配器时从数据库中获取所有数据。将此数据放入列表并在适配器中使用该列表。这将提高性能,使您的代码更加简洁,并且更容易发现错误。 【参考方案1】:

这是因为RecyclerView 的工作方式,与您访问联系人数据的方式无关。 RecyclerView 只会为一次适合屏幕的每个视图创建一个 ViewHolder,然后当它们滚动到屏幕外时回收这些视图。然后该视图的新内容将应用到onBindViewHolder()

由于您之前可能已为 ViewHolder.textHomePhoneViewHolder.textWorkPhone 文本视图分配了文本,因此当这些视图持有者被回收时,该文本仍然存在。因此,如果新联系人只有手机号码,则家庭号码和工作号码的文本仍将由占用该ViewHolder的先前联系人填写。

要解决此问题,您需要检查联系人没有是否具有每种类型(移动、家庭和工作)的编号,如果有,请将相应 TextView 的可见性设置为View.GONE.

一个简单的方法是在循环之前创建三个布尔值,然后检查它们:

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

【讨论】:

【参考方案2】:

我认为问题出在以下行:

if (dataCursor.moveToFirst())

您将数据光标移动到每次调用中的第一个元素,这是不必要的,这将撤消函数顶部的以下行:

dataCursor.moveToPosition(position);

如果您删除 if 语句,它应该可以正常工作

【讨论】:

嗨@pooya 你的解决方案仍然有同样的问题 @D.O.从这里进行调试非常困难,但是您的代码中也存在一些语义问题,例如,在此之前 (phones.moveToNext()) 需要有phones.moveToFirst()。请看看您是否可以先纠正这些问题以帮助获得更可靠的输出 这是我试图在我的代码中读取所有电话号码的实现。也许这可以帮助你给我一些解决方案。是@anivaler ***.com/questions/2356084/… 的答案 @D.O.在 RecyclerView 中,您应该做的只是在用户滚动并且数据失效时更新每一行的数据,因此您无法读取 onBindViewHolder 中的所有内容

以上是关于滚动视图时,Recyclerview 在contactsContract 中更改我的phoneNumber 的值的主要内容,如果未能解决你的问题,请参考以下文章

RecyclerView的行项目视图隐藏/显示在Recyclerview的滚动上搞砸了

RecyclerView - 如何平滑滚动到嵌套滚动视图内某个位置的项目顶部?

在 RecyclerView 项目内滚动

RecyclerView 水平滚动对齐在中心

Recyclerview 在滚动期间更改项目

当另一个滚动时如何隐藏recyclerview