gpt4 book ai didi

java - 在删除项目后更新 StableIdKeyProvider 缓存和 RecyclerView/SelectionTracker 在新选择时崩溃

转载 作者:太空宇宙 更新时间:2023-11-03 12:14:01 26 4
gpt4 key购买 nike

准备:

RecyclerViewRecyclerView.Adapter 绑定(bind)到 SQLite Cursor(通过 ContentProvider && Loader)。 RecyclerViewRecyclerView.AdapterSelectionTracker 链接为 design suggests .SelectionTracker 使用 StableIdKeyProvider 构建。

第一步 - 删除一个项目:

  1. 长按选择 RecyclerViews 的项目(为 SelectionTrackerSelectionObserver 干杯),绘制操作栏上下文菜单,开火删除 Action ,执行SQL删除任务。
  2. SQL删除结束后,用
    做Cursor Loader更新restartLoader 调用。
  3. onLoadFinished 触发,获得新的 Cursor,on
    调用了 RecyclerView.Adapter 方法 notifyDataSetChanged
  4. RecyclerView.Adapter 重绘RecyclerView 内容,一切如常好。

第二步 - 选择其他项目。崩溃:

java.lang.IllegalArgumentException
at androidx.core.util.Preconditions.checkArgument(Preconditions.java:38)
at androidx.recyclerview.selection.DefaultSelectionTracker.anchorRange(DefaultSelectionTracker.java:269)
at androidx.recyclerview.selection.MotionInputHandler.selectItem(MotionInputHandler.java:60)
at androidx.recyclerview.selection.TouchInputHandler.onLongPress(TouchInputHandler.java:132)
at androidx.recyclerview.selection.GestureRouter.onLongPress(GestureRouter.java:96)
at android.view.GestureDetector.dispatchLongPress(GestureDetector.java:779)
at android.view.GestureDetector.access$200(GestureDetector.java:40)
at android.view.GestureDetector$GestureHandler.handleMessage(GestureDetector.java:293)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

在删除项目的过程中,我在第一步看到的内容。当 StableIdKeyProvider 使用 onDetached ViewHolder 项目做内部工作时,它看不到以前分配的 ViewHolder 的位置适配器:

   void onDetached(@NonNull View view) {
RecyclerView.ViewHolder holder = mRecyclerView.findContainingViewHolder(view);
int position = holder.getAdapterPosition();
long id = holder.getItemId();
if (position != RecyclerView.NO_POSITION && id != RecyclerView.NO_ID) {

int position 这里是RecyclerView.NO_POSITION

这就是为什么 RecyclerView 在 StableIdKeyProvider 的缓存包含 ID 的旧快照而没有删除影响之后崩溃。

问题是 - 为什么?以及如何更新 StableIdKeyProvider 的缓存?

另一个注意事项:当我阅读 RecyclerView 代码时,我看到了这条评论:

     * Note that if you've called {@link RecyclerView.Adapter#notifyDataSetChanged()}, until the
* next layout pass, the return value of this method will be {#NO_POSITION}.

我不明白这句话的确切含义。也许我遇到了所描述的情况 - notifyDataSetChanged 在不合适的时间调用?或者我需要调用它两次?

附言。文字描述不好意思,有很多复杂的代码

最佳答案

我结束了玩 StableIdKeyProvider 并切换到我自己的 ItemKeyProvider 实现:

new ItemKeyProvider<Long>(ItemKeyProvider.SCOPE_MAPPED) {
@Override
public Long getKey(int position) {
return adapter.getItemId(position);
}

@Override
public int getPosition(@NonNull Long key) {
RecyclerView.ViewHolder viewHolder = recyclerList.findViewHolderForItemId(key);
return viewHolder == null ? RecyclerView.NO_POSITION : viewHolder.getLayoutPosition();
}
}

Crash 没有了,RecyclerView 的导航/选择/修改看起来没问题。StableIdKeyProvider 怎么样?...嗯,可能它不是为处理 RecyclerView 的可变内容而设计的。

更新 2021-12-03

上周我在 RecycleView 上进行了新一轮的斗争。正如问题中提到的 - 确切的问题是 StableIdKeyProvider 的缓存。切换到 ItemKeyProvider 是解决方法。正如 StableIdKeyProvider 的代码所解释的那样,chache 绑定(bind)到窗口的事件:附加和分离。所以,我在上面引用的评论 - 正是问题所在:当新的 Cursor 到达时 - 将 Cursor 重新附加到 Adapter并通知 - 需要在正确的时间开火。 “合适的时间”- 将此作业排入布局消息线程。通过这种方式,RecyclerView 和底层“工具箱”可以自行正确执行更新。为此,只需在 post runnable 方法中提供一个新的 Cursor 即可。代码:

@Override
public void onLoadFinished(@NonNull Loader<Cursor> loader, Cursor data) {
recycler.post(new Runnable() {
@Override
public void run() {
adapter.swapCursor(data);
}
});
...

关于java - 在删除项目后更新 StableIdKeyProvider 缓存和 RecyclerView/SelectionTracker 在新选择时崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53523318/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com