首页 > 其他分享 >Android TV上Recyclerview焦点控制心得

Android TV上Recyclerview焦点控制心得

时间:2024-08-01 16:50:47浏览次数:8  
标签:TV 焦点 刷新 position Android Recyclerview post View

背景:

项目里有一个定时刷新的需求,刷新的数据是填充在Recyclerview里的

 

问题:

用户可能已经滑动Recyclerview到某一位置,这时候触发了定时刷新任务,新的数据到来会触发Recyclerview的adapter.notifydatasetchanged(),这时候

1.数据已经刷新,Recyclerview应该会滑动到初始位置

2.Recyclerview焦点丢失

 

探讨:

对于第一点,很奇怪没有发生,Recyclerview刷新数据后竟然保持在了原来的滚动位置没有变化,这里暂时没想明白

难道跟我用的控件有关系?

implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.7'

自定义adapter继承BaseQuickAdapter,并且使用setList刷新数据源,看了下setList的实现,没有发现有特殊处理的地方。

最开始想的是如果发生问题1,是不是可以通过setDiffNewData之类方式的进行局部刷新解决,但是很奇怪没有发生。

 

对于问题2,焦点确实会丢失,因为数据源变化了,重新绘制了Recyclerview。

但在应用场景里,用户很难接受焦点瞬移,导致操作不连续。

这里我们很容易想到的方案就是,在刷新数据源之前,先判断当前Recyclerview是否获取了焦点,如果有焦点,则将焦点位置记住,在刷新数据源后,强行将焦点位置还原回去。

那么问题就变成了

1.如何判断当前Recyclerview是否有焦点(当前用户可能用遥控器操控其它,焦点不一定在Recyclerview上,那么就不需要我们将焦点还原到Recyclerview的先前位置)

2.如何记录焦点的位置(当前焦点在Recyclerview的第几条,即position)

3.在数据刷新完成后还原位置(即将焦点还原到第2步中的position)

经过一系列的查询,我定义了如下方法

private int getRecyclerviewFocusPosition(){
  //默认的无意义的焦点位置,用于该方法区分返回的position是否是有效值
  int position = -100;
  //解决第1点,判断是否有焦点,如果焦点不在Recyclerview,则此时返回null 
  View focusView = binding.recyclerview.getFocusedChild();
    if (focusView != null){
    //解决第2点,记录了焦点的position
     position = binding.recyclerview.getChildAdapterPosition(focusView);
    }
  logger.i("getRecyclerviewFocusPosition: " + position);
    return position; 
}

该方法一定要在setList之前调用,因为此时才是检测Recyclerview是否有焦点的最佳时机(提前调用可能用户在后续操作中已将焦点移出Recyclerview,那么记录的position就没有意义),

然后在Recyclerview刷新了最新数据源后立马恢复焦点绘制

 binding.recyclerview.post(() -> {
    if (focusPosition > -100){
        binding.recyclerview.getLayoutManager().
      findViewByPosition(focusPosition).requestFocus(); } });

当然最好的时机是监听Recyclerview绘制完成后触发,这里由于我们的数据源比较少且布局不复杂,直接view.post也是正常可行的

 

扩展:

另外查了下view.post方法

1、View.post(Runnable) 内部会自动分两种情况处理,当 View 还没 attachedToWindow 时,会先将这些 Runnable 操作缓存下来;否则就直接通过 mAttachInfo.mHandler 将这些 Runnable 操作 post 到主线程的 MessageQueue 中等待执行。

2、如果 View.post(Runnable) 的 Runnable 操作被缓存下来了,那么这些操作将会在 dispatchAttachedToWindow() 被回调时,通过 mAttachInfo.mHandler.post() 发送到主线程的 MessageQueue 中等待执行。

3、mAttachInfo 是 ViewRootImpl 的成员变量,在构造函数中初始化,Activity View 树里所有的子 View 中的 mAttachInfo 都是 ViewRootImpl.mAttachInfo 的引用。

4、mAttachInfo.mHandler 也是 ViewRootImpl 中的成员变量,在声明时就初始化了,所以这个 mHandler 绑定的是主线程的 Looper,所以 View.post() 的操作都会发送到主线程中执行,那么也就支持 UI 操作了。

5、dispatchAttachedToWindow() 被调用的时机是在 ViewRootImol 的 performTraversals() 中,该方法会进行 View 树的测量、布局、绘制三大流程的操作。

6、Handler 消息机制通常情况下是一个 Message 执行完后才去取下一个 Message 来执行(异步 Message 还没接触),所以 View.post(Runnable) 中的 Runnable 操作肯定会在 performMeaure() 之后才执行,所以此时可以获取到 View 的宽高或者其他的计算逻辑。

标签:TV,焦点,刷新,position,Android,Recyclerview,post,View
From: https://www.cnblogs.com/terrorists/p/18331606

相关文章

  • 谷歌TV ADB
    AndroidTV的遥控器,基于ADBShell命令ADBRemoteATV是一个AndroidTV的遥控器,基于 ADBShell 命令,泛用性更高。下面的shell命令,是软件的基本原理,通过shell命令可模拟物理遥控器的基本按键,此外还可以快捷启动指定APP、借助手机软键盘输入中/英字符等。 #输入......
  • Android开发 - (适配器)Adapter类中SimpleAdapter实现类详细解析
    具体作用SimpleAdapter的主要作用是简化将数据源(如List<Map<String,Object>>)绑定到视图组件(如TextView、ImageView等)的过程。它可以根据指定的键将数据映射到指定的视图组件上,从而快速实现数据的展示参数、方法解析SimpleAdapter(Contextcontext,List<?extendsMap......
  • android.uid.system sendBroadcast失效的问题
    如果是系统应用android:sharedUserId="android.uid.system"报这个错 Callingamethodinthesystemprocesswithoutaqualifieduser:android.app.ContextImpl.sendBroadcast:1188android.content.ContextWrapper.sendBroadcast:解决添加如下权限<uses-permissionandroi......
  • Android开发 - (适配器)Adapter类中BaseAdapter实现类详细解析
    具体作用BaseAdapter是Android开发中一个非常重要的Adapter(适配器)基类。它提供了创建自定义适配器的基本实现,使开发者可以根据具体需求创建适用于不同视图(如ListView、GridView)的数据适配器。以下是BaseAdapter的主要作用:提供基本接口实现BaseAdapter实现了ListAd......
  • Android 10.0 第三方app授予DeviceOwner权限调用系统reboot,显示隐藏app,锁屏,禁用app
    1.前言 在10.0的系统rom定制化开发中,在有些客户开发app的功能中,需要系统授予app的DeviceOwner权限,然后app就可以实现重启关机禁用下拉通知栏,显示隐藏app,等功能,首选需要在app和framework中配置相关功能,接下来具体分析相关功能的实现2.第三方app授予DeviceOwner权限调用系......
  • 信步漫谈之Android——HelloWorld
    目录目标1资源2第一个HelloWorld程序3项目结构说明3.1目录结构3.2结构说明4在App中添加日志后续补充参考资料目标学习搭建Android的开发环境sayhelloworld1资源官网教程:https://developer.android.com/courses开发工具AndroidStudio下载路径:https://d......
  • Android开发 - (适配器)Adapter类中CursorAdapter实现类详细解析
    作用将Cursor对象中的数据与AdapterView组件(如ListView、GridView等)进行绑定。以下是CursorAdapter的主要作用:1.数据源绑定数据源连接:CursorAdapter通过Cursor对象作为数据源,实现了从数据库或其他数据源(如ContentResolver查询结果)中读取数据的功能。这使得开发者能够轻松地......
  • Android Wifi 扫描相关知识
    1.主动扫描和被动扫描1.1主动扫描(ActiveScanning)主动扫描是WIFI设备(STA,即Station,如手机、笔记本电脑等)在信道上主动广播一个探测请求(ProbeRequest),并等待接入点(AP)的响应。这种扫描方式更加主动,能够更快地发现周围的WIFI网络,但也可能对电池寿命和性能功耗产生一定的影响。......
  • Android开发之热修复
    #来自ウルトラマンゼロ(哉阿斯)1热修复核心资源修复代码修复动态链接库修复2资源修复资源修复参考 InstantRun 的资源修复原理。创建AssetManager,通过反射调用addAssetPath方法加载外部的的资源。将AssetManager类型的mAssets字段的引用全部替换成新创建的......
  • Android RecyclerView
    AndroidRecyclerView介绍RecyclerView是Android的一个高级视图组件,旨在显示大量数据的列表或网格。相比于传统的ListView,RecyclerView提供了更多的功能和灵活性。AdapterAdapter是RecyclerView的数据源,负责将数据绑定到ViewHolder上。常见的Adapter实现包括Recy......