RecyclerView findViewHolder null for off-screen items

RecyclerView findViewHolder null for off-screen items

[第一次提问,第一次 android 编码所以如果我做错了什么我道歉]

我正在尝试更改我的回收站的 itemview 中的值。但是,如果该 itemview 恰好在屏幕外,则 findViewBy[layout,adapter,or id] 出现 null。

public void setUserActive(UserListAdapter adapter, RecyclerView recyclerView, int position, View v) {recyclerView.findViewHolderForItemId(adapter.getItemId(position));
    TextView txtActive = (TextView) vh.itemView.findViewById(R.id.user_isActive);
    txtActive.setText("Active");
    UserListAdapter.ViewHolder inactivevh = (UserListAdapter.ViewHolder) recyclerView.findViewHolderForItemId(adapter.getItemId(adapter.getActiveUserPosition()));
    TextView txtInActive = (TextView) inactivevh.itemView.findViewById(R.id.user_isActive);
    txtInActive.setText("");
    adapter.setActiveUserPosition(position);
}

我尝试了几种不同的方法,从使用

  UserListAdapter.ViewHolder vh = (UserListAdapter.ViewHolder) recyclerView.findViewHolderForLayoutPosition(position);

UserListAdapter.ViewHolder inactivevh = (UserListAdapter.ViewHolder) recyclerView.findViewHolderForAdapterPosition(position)

当本应处于非活动状态的视图离开屏幕时,它们都会失败。

我已将适配器设置为 hasStableIDs = true notifydatasetchanged 似乎也没有帮助。

如果项目在屏幕上(布局),您可以使用您描述的方法方便地获取其视图持有者。 如果某个项目不在屏幕上,它将在通过 onBindViewHolder 滚动进入后立即更新。 如果它没有滚动进入,则不会呈现给用户,因此任何更新它的尝试都是对处理能力的浪费(除了不可能,因为该项目没有分配视图持有者)。

含义:以onBindViewHolder能够提取最新数据的方式实现您的适配器。看起来你已经准备就绪,可以使用它了:

public void setUserActive(UserListAdapter adapter, RecyclerView recyclerView, int position) {
    // Retrieve the old active user ID so we can mark him deactivated.
    final int oldUserActivePosition = adapter.getActiveUserPosition();

    // Setup the adapter with current data.
    adapter.setActiveUserPosition(position);

    // Do NOT use stable IDs and this method. It just doesn't work as expected.
    // recyclerView.findViewHolderForItemId(adapter.getItemId(position));

    // Activate new user.
    UserListAdapter.ViewHolder holder = (UserListAdapter.ViewHolder) recyclerView.findViewHolderForAdapterPosition(position);
    if (holder == null) {
        // The item is off screen, no need to update it yet.
    } else {
        // Update the on screen item. The logic is already implemented in the adapter.
        adapter.onBindViewHolder(holder, position);
    }

    // Deactivate previous user.
    holder = (UserListAdapter.ViewHolder) recyclerView.findViewHolderForAdapterPosition(oldUserActivePosition);
    if (holder != null) {
        adapter.onBindViewHolder(holder, oldUserActivePosition);
    }
}

当然要简化代码中的 if-else 块。

编辑:

我刚刚意识到原来的解决方案是多么不必要的复杂。只要适配器可以响应您在 onBindViewHolder 中需要的所有事件,并且绑定非常简单,这就足够了:

public void setActiveUserPosition(int position) {
    if (mActiveUserPosition != position) {
        int oldPosition = mActiveUserPosition;
        mActiveUserPosition = position;
        notifyItemChanged(oldPosition);
        notifyItemChanged(position);
    }
}

您现在需要调用的是 adapter.setActiveUserPosition(position);,这会使 setUserActive 方法过时。