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



我正在尝试复制Recyclerview方法的操作,其中我在ArrayList项目名称中有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循环只是改变最后一张卡的颜色,尽管它同时向notifyItemChanged((提供位置值1,2,3。


但当通过安卓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迭代过程中,我会根据新值创建(或修改(一个新的List
  3. 然后我会向适配器提交一个新的列表(ListAdapter有一个名为submitList(T)的方法

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

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

这里有其他选择,但我会先试试ListAdapter,它包含在Android中,可能会很好地工作。

如果你需要帮助设置列表适配器,并且因为我已经被问了9000多次这个问题,我在GitHub上创建了我可以想象的最简单的回收器视图示例:(

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

建议:

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

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,而不是调用单个回收器视图项进行更新。

相关内容

最新更新