首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么RecyclerView的notifyItemChanged(int位置)只工作一次而不是三次?

为什么RecyclerView的notifyItemChanged(int位置)只工作一次而不是三次?
EN

Stack Overflow用户
提问于 2021-06-08 15:51:12
回答 3查看 101关注 0票数 0

我试图复制回收视图方法的操作,其中我有3个项目在ArrayList项目名中,也存储在sqlite表中。对应于每个项目名称,在该表中分配一个'id‘。在这里,我希望对于下面的每一次迭代,所有3个项目都应该根据Adapter类的onBindViewHolder()方法中定义的条件改变颜色。

代码语言:javascript
复制
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()方法负责根据主类中position变量的值更改卡片的颜色。

代码语言:javascript
复制
@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张卡片都将逐个变为红色。截击方法如下所示:

代码语言:javascript
复制
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张卡的颜色所需的输出。

EN

回答 3

Stack Overflow用户

发布于 2021-06-08 19:57:40

然后,我会向适配器提交一个新的列表(ListAdapter有一个名为submitList(T).的方法,

  • I会向适配器提交一个新的列表

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

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

这里有其他选择,但我会先试试ListAdapter,它包含在安卓系统中,可能会运行得很好。

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

票数 1
EN

Stack Overflow用户

发布于 2021-06-08 19:28:53

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

Recommendations:

将日志语句添加到对notifyItemChanged()onBindViewHolder()的调用中。您很可能会在调用onBindViewHolder()之前看到notifyItemChanged()调用。在onBindViewHolder()中记录position和Security.alert_position的值,这应该可以解释为什么你会看到你看到的东西。

代码语言:javascript
复制
Log.d("MY-TAG", String.format("calling notifyItemChanged(%d)", alert_position));

onBindViewHolder()中的

代码语言:javascript
复制
Log.d("MY-TAG", String.format("onBindViewHolder(%d), Security.alert_position=%d", position, Security.alert_position));

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

虽然这个建议不会解决你的程序逻辑,但它有望帮助你理解正在发生的事情。

票数 0
EN

Stack Overflow用户

发布于 2021-06-17 01:20:24

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

代码语言:javascript
复制
 if (tokens[0].equals("1")) {
                     power_position.add(id);
                     userAdapter.notifyDataSetChanged();
                 }

并且在Recyclerview适配器类中。

代码语言:javascript
复制
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);
        }
    }

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67883519

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档