为啥 notifyItemChanged(position) 不更新 RecyclerView 中的所有项目?
Posted
技术标签:
【中文标题】为啥 notifyItemChanged(position) 不更新 RecyclerView 中的所有项目?【英文标题】:Why notifyItemChanged(position) not updating all the items in RecyclerView?为什么 notifyItemChanged(position) 不更新 RecyclerView 中的所有项目? 【发布时间】:2021-08-23 23:17:54 【问题描述】:在从 firebase 数据库中获取某些值后,我正在尝试在 recyclerview 中同时更新 3 个项目。下面的方法对 ArrayList itemname 进行三次迭代,每个值都调用 SecurityAlertSensor(itemname) 方法。
在每次迭代的此方法中,回收器视图中的相应项目应更改。就像如果从 SQLite DB 获取的 id 是 1,那么回收器视图的第一项将被更新,并且在下一次迭代中,如果 id 是 2,那么第二项将针对第 3 项进行类似更新。
但是使用下面的代码,只有回收器视图的三项中的最后一项正在更新前两项,这不起作用。
for (int i=0; i<itemname.size(); i++)
if (isOnline())
SecurityAlertSensor(itemname.get(i));
else if(!isOnline())
Toast.makeText(getApplicationContext(), "Update Failed!", Toast.LENGTH_SHORT).show();
此方法在每次迭代时从 Firebase DB 获取值,如果值为“1”,则调用 notifyItemChanged(position) 以更新 recyclerview 中的特定项目。
private void SecurityAlertSensor(final String email)
sec_ref2 = sec_ref1.child(email);
sec_ref2.addValueEventListener(new ValueEventListener()
int id;
@SuppressLint("SetTextI18n")
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot)
String value = dataSnapshot.getValue(String.class);
if (value != null)
if (value.contains("0") || value.contains("1"))
Toast.makeText(Security.this, value, Toast.LENGTH_SHORT).show();
String[] tokens = value.split(",");
power_state = tokens[0];
ContentValues values = new ContentValues();
values.put(SecurityDatabaseContract.UserDatabase2.SEC_NAME_COL4, tokens[0]);
values.put(SecurityDatabaseContract.UserDatabase2.SEC_NAME_COL5, tokens[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();
if (tokens[1].equals("1"))
alert_position = id;
userAdapter.notifyItemChanged(alert_position);
sec_ref2.removeEventListener(this);
else
Toast.makeText(Security.this, "Device Not Found!", Toast.LENGTH_SHORT).show();
@Override
public void onCancelled(@NonNull DatabaseError error)
Toast.makeText(getApplicationContext(), "Not Found!", Toast.LENGTH_LONG).show(); // Failed to read value
);
在 Recyclerview Adapter 类的 onBindViewHolder 方法中。每次在主类中实例化 notifyItemChanged(position) 时都会调用它。
public void onBindViewHolder(@NonNull final UserViewHolder holder, final int position)
if(position == Security.alert_position)
holder.state.setText("< Activated >");
holder.state.setTextColor(Color.RED);
holder.cards.setBackgroundColor(0x33FF0000);
【问题讨论】:
【参考方案1】:你的问题在onBindViewHolder()
:
if(position == Security.alert_position)
您依赖于在每次迭代中将Security.alert_position
的值设置为项目位置。我猜对notifyItemChanged()
的每次调用都不会立即对onBindViewHolder()
进行调用,但是对onBindViewHolder()
的调用是异步的,并且会在以后发生。此时Security.alert_position
已经设置为第三个值,所以每次输入onBindViewHolder()
时,Security.alert_position
的值就是你设置的最后一个值。
您可以添加一些调试日志来验证我的假设。一般来说,您的架构并不好,因为您在另一个地方做某事时依赖于存储在一个地方的状态。
【讨论】:
感谢大卫的建议。但是,为什么在通过 Volley 从 mysql 获取相同数据时,同样的技巧会起作用(所有三个项目都在正确更新)?另外,您能否为此提出一些解决方法? 我不太了解 Volley 的工作原理,无法回答这个问题,抱歉。解决方法?从您发布的代码中,我对您在这里尝试做的事情知之甚少。不过,通常这种架构是错误的。以上是关于为啥 notifyItemChanged(position) 不更新 RecyclerView 中的所有项目?的主要内容,如果未能解决你的问题,请参考以下文章
Recyclerview在Android中notifyItemChanged后防止触摸事件
Android RecyclerView Adapter notifyItemChanged() 获取 IllegalStateException 已经在池中
Android-RecyclerView系列 notifyItemChanged() - 实现单选选中状态更新
Android RecycleView notifyItemChanged()刷新闪烁异常处理