美文网首页Android TV
RecyclerView进行数据更新时焦点丢失的解决方案

RecyclerView进行数据更新时焦点丢失的解决方案

作者: RainFool | 来源:发表于2016-07-28 16:13 被阅读3864次

    RecyclerView进行数据更新时焦点丢失的解决方案

    在使用RecyclerView时,难免会用到adapter的notifyDataSetChanged方法来更新数据,其实notify**Changed系列方法都存在一个已知的焦点丢失的bug,如果在notify之后重新手动requestFocus,又会导致焦点可能不对应的问题。

    可以使用如下步骤规避此问题:

    1.为adapter提供stableId
    stableId在Listview和RecyclerView中都被用来定位一个item,官方建议使用item本身的hashcode或item内部的属性的hashcode,来唯一标识一个item,因此,需要在adapter中复写此方法:

        @Override  
        public long getItemId(int position) {  
            return position;  
        }
    

    更简单一点,可以如上代码所示直接return item的position。
    2.设置item的setHasStableIds()为true:

        adapter.setHasStableIds(true);  
    

    在listview中也有复写此方法的方案。
    3.在官方推荐的做法来看,这两步已经可以保存recyclerview的焦点了,但是使用notify系列方法仍然会出现focus丢失的问题,现在官方已经承认这是一个bug,可以暂时使用禁用notifyDataSetChanged动画的方法来规避:

        mRecyclerView.setItemAnimator(null);
    

    这种写法禁用了所有的item动画,你也可以只禁用notifyDataSetChanged来实现同样的效果。

    更多关于stableId的讨论请前往[http://stackoverflow.com/questions/10267731/android-how-to-make-an-adapter-with-stable-ids]

    更多关于禁用动画的方法请前往:[http://stackoverflow.com/questions/29873859/how-to-implement-itemanimator-of-recyclerview-to-disable-the-animation-of-notify]

    关于第三步提到的bug请前往:[https://code.google.com/p/android/issues/detail?id=204277]

    相关文章

      网友评论

      • yqyzxd:item滑出页面后焦点就没了,怎么破
        RainFool:item 滑出页面指的是滑出了屏幕吗,view已经到显示区域外,自然是没有焦点的啊。
        如果你是用鼠标或者手势滑出去的,其实应该在一开始发生touchEvent的时候就让所有view失去焦点,因为这时候已经切换到了TouchMode,焦点只在非TouchMode才有意义
      • 53d2ec635bc4:非常感谢,解决了我的问题:clap:
      • xtl1889:有用!感谢!
      • a2115975576b:GridLayoutManager gm = new GridLayoutManager(this, 9){

        @Override
        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        super.onLayoutChildren(recycler, state);
        Log.e(TAG, "onLayoutChildren: didStructureChange : " + state.didStructureChange() + " willRunPredictiveAnimations:" + state.willRunPredictiveAnimations() + " willRunSimpleAnimations:" + state.willRunSimpleAnimations() + " isPreLayout:" + state.isPreLayout() );
        // notifyDataSetChange() 完成後呼叫 :
        if(state.didStructureChange() && !state.willRunSimpleAnimations() && !state.willRunPredictiveAnimations() && !state.isPreLayout()){
        // 這邊呼叫 recyclerView.getChildAt(position).requestFocusFromTouch();
        // recyclerView = 你的recyclerView
        // position = 你要focus的 item 位置
        }
        }
        };
        recyclerView.setLayoutManager(gm); // 可以換成 其他layoutManager
      • _Rainco:为什么没有用啊,我调用notifydatasetchanged后焦点仍然跑到第一个item去了,能发个demo吗 万分感谢。
      • cbb290675031:好像没有用,我是这种情况,一个页面有两个RecyclerView,当焦点在右边RecyclerView的item中,点击item刷新这个RecyclerView,结果它的焦点自动就跑到左边那个RecyclerView里面第一个item中去了,快疯了
        砺雪凝霜:谢谢,折磨我好久的bug终于解决了
        cbb290675031:@RainFool 66666到不行
        RainFool:我也做过这种需求的东西,焦点跑到左边是因为你在刷右边数据的时候,右边RecyclerView已经没有View给它去focus了。
        目前我自己的做法是:
        将右边RecyclerView放到一个Viewgroup中,这个ViewGroup的 focusable="true",当你要刷新右边RecyclerView的时候,记录当前焦点位置,手动让这个ViewGroup requestFocus,然后等刷新结束,scrollTo上次记录的位置,再获取对应View,然后再手动RequestFocus
      • cfe1c1fef66e:太感谢了 帮上大忙了
      • initialjie:感谢啊。。做的TV开发,被这BUG搞死了。。
        RainFool:@initialjie 同TV开发,整体就跟这些焦点打交道,互相帮助

      本文标题:RecyclerView进行数据更新时焦点丢失的解决方案

      本文链接:https://www.haomeiwen.com/subject/ljmajttx.html