为什么 RecyclerView 的 notifyItemChanged(int position) 只工作一次多于三次?

如何解决为什么 RecyclerView 的 notifyItemChanged(int position) 只工作一次多于三次?

我正在尝试复制 Recyclerview 方法的操作,其中我在 ArrayList itemname 中有 3 个项目并且还存储在 sqlite 表中。对应于每个项目名称,在表中分配了一个“id”。在这里,我希望对于下面的每个迭代,所有 3 个项目都应根据 Adapter 类的 onBindViewHolder() 方法中定义的条件改变颜色。

for (int i=0; i<itemname.size(); i++) {   
String query = "SELECT id FROM sec_table WHERE address='"+itemname.get(i)+"'";
                 Cursor c1 = SecDB.rawQuery(query,null);

                 if (c1 != null && c1.getCount() != 0)
                 {
                     while (c1.movetoNext()) {
                         id = c1.getInt(c1.getColumnIndex("id"));
                     }
                        c1.close();
                 }

      alert_position = id;                // Class variable 'alert_position'
      userAdapter.notifyItemChanged(alert_position);
}

onBindViewHolder() 方法负责根据 Main 类中位置变量的值更改卡片的颜色。

@Override                // Inside the Adapter class
public void onBindViewHolder(@NonNull final UserViewHolder holder,final int position) {
    final SecurityDetails userDetails = secDetailsList.get(position);
    LogsDatabaseHelper logsDBHelper = new LogsDatabaseHelper(context);


    SecurityDatabaseHelper secDBHelper = new SecurityDatabaseHelper(context);
    LogsDB = logsDBHelper.getWritableDatabase();
    SecDB = secDBHelper.getWritableDatabase();

    if (requestQueue==null)
    requestQueue = Volley.newRequestQueue(context);      // Creating RequestQueue...

    holder.tvName.setText(userDetails.getName());

    if(position == Security.alert_position) {
        Toast.makeText(context,position+"",Toast.LENGTH_SHORT).show();
        holder.state.setText("< Activity Detected >");
        holder.state.setTextColor(Color.RED);
        holder.cards.setBackgroundColor(0x33FF0000);
    }
  }

这里上面的 for 循环只是改变了最后一张卡片的颜色,尽管它同时将位置值 1,2,3 提供给 notifyItemChanged()。


但是当通过 android Volley 执行相同的卡片更新逻辑时,所有 3 张卡片都会一张一张地变红。截击方法如下图所示:

for (int i=0; i<itemname.size(); i++) {   // Calls the Volley method with different items name from arraylist
      CardsUpdate(itemname.get(i));
}

private void CardsUpdate(final String email) {
    StringRequest stringRequest = new StringRequest(Request.Method.POST,"http://plateau.com/SecuritySensorUpdate.PHP",new Response.Listener<String>()
    {
        int id;
        @Override
         public void onResponse(String ServerResponse) {
            if (ServerResponse.equalsIgnoreCase("1")) {
                ContentValues values = new ContentValues();
                values.put(SecurityDatabaseContract.UserDatabase2.SEC_NAME_COL4,"1");
                SecDB.update(SecurityDatabaseContract.UserDatabase2.TABLE_NAME2,values,"address='" + email + "'",null);

                String query = "SELECT id FROM sec_table WHERE address='" + email + "'";
                Cursor c1 = SecDB.rawQuery(query,null);

                if (c1 != null && c1.getCount() != 0) {
                    while (c1.movetoNext()) {
                        id = c1.getInt(c1.getColumnIndex("id"));
                    }
                    c1.close();
                }

                alert_position = id;
                userAdapter.notifyItemChanged(alert_position);
            }
            else
                Toast.makeText(Security.this,ServerResponse,Toast.LENGTH_SHORT).show();
        }},new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError volleyError) {
                  //  Toast.makeText(Security.this,volleyError.toString(),Toast.LENGTH_SHORT).show();
                }
            })
    {
        @Override
        protected Map<String,String> getParams()
        {
            Map<String,String> params = new HashMap<>();
            params.put("email",email);
            return params;
        }};

    requestQueue.add(stringRequest);        // Adding the StringRequest object into requestQueue.
}

请提出一些解决方法来实现更新所有 3 张卡片的颜色的期望输出

解决方法

  1. 我会使用 ListAdapter<T,K>(来自 RecyclerView)。
  2. 在 Cursor 迭代期间,我会根​​据新值创建(或修改)一个新列表。
  3. 然后我会向适配器提交一个新列表(ListAdapter 有一个名为 submitList(T) 的方法。

由于您需要向 ListAdapter 提供“Diff Util”回调,因此它将负责重新绑定数据已更改的视图。

如果您真的想要“实时”一个一个地改变,那么您需要更深入地研究让 ViewModel 公开一个状态(可能是一个 Flow)可以观察每个emit(...)并做出反应。

这里有替代方案,但我会先尝试 ListAdapter,它包含在 Android 中,并且可能会正常工作。

如果您在设置列表适配器方面需要帮助,并且因为我被问过 9000 多次这个问题,我已经创建了 the simplest recycler view sample over at GitHub 我可以想象:)

,

notifyItemChanged() 的调用不是同步的,即 onBindViewHolder() 将在稍后调用。到调用 onBindViewHolder() 时,静态属性 Security.alert_position 包含最新值(从第三次到循环)。

建议:

将日志语句添加到您对 notifyItemChanged()onBindViewHolder() 的调用中。您可能会看到 notifyItemChanged() 调用先于 onBindViewHolder() 调用。记录 Security.alert_position 中的位置和 onBindViewHolder() 值,这应该可以解释为什么您会看到您所看到的内容。

Log.d("MY-TAG",String.format("calling notifyItemChanged(%d)",alert_position));

在 onBindViewHolder()

Log.d("MY-TAG",String.format("onBindViewHolder(%d),Security.alert_position=%d",position,Security.alert_position));

我怀疑您会看到对 onBindViewHolder() 的三个调用显示了正确的位置值 (1,2,3),但 Security.alert_position 将始终为 3。

虽然此建议无法解决您的程序逻辑,但它有望帮助您了解正在发生的事情。

,

得到解决方案。通过向 Arraylist 添加位置,然后通过迭代在 Recyclerview 适配器类中的 for 循环进一步调用该 ArrayList,可以实现相同的效果。

 if (tokens[0].equals("1")) {
                     power_position.add(id);
                     userAdapter.notifyDataSetChanged();
                 }

在 Recyclerview 适配器类中。

for (int i=0; i<Security.alert_position.size(); i++) {
        if (position == Security.alert_position.get(i)) {
            holder.state.setText("< Data Changed >");
            holder.state.setTextColor(Color.RED);
            holder.cards.setBackgroundColor(0x33FF0000);
        }
    }

这将立即刷新 Recyclerview,而不是调用单个回收器视图项进行更新。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?