记录关于Note接入侧边栏小工具相关事情,包括需求、分析、设计、实现等
🤑 背景
- 在海外教育的整机上,Note是作为书写应用,是终端用户场景的高频使用应用之一
- 为了用户交互需要,整机在所有的页面启动之后,默认都会有侧边栏UI,用于方便用户做应用切换等操作
- 在侧边栏中,有各种应用的入口,同时,还集成了各种常用的小工具入口,如计时器、录屏工具、云课堂、聚光灯等
🥵 需求
- 客户在使用过程中,发现Note是主要使用应用,而侧边栏的部分小工具,经常和Note在教学场景会结合起来使用,具有较高的绑定关系
- 为了方便用户使用唤起,客户反馈,希望能将这部分高频使用的小工具入口,添加到Note工具栏中
🥸 前期考虑
由于小工具入口,原先是在侧边栏中做,且不同客户,对于侧边栏,会有不同的定制,note如果直接接入,可能会在后期面临不同客户的侧边栏定制需求时,Note没有及时同步这些定制,从而给客户带来问题,如果Note每次都去同步这些需求,无异于将侧边栏的部分工作,重复到Note中,后续还会带来无穷无尽的开发投入成本。
并且由于Note是独立于侧边栏的,在多语言场景下,还要做翻译适配。
综上,Note不应该单独接入小工具,最好是复用侧边栏的能力,Note只作为入口,和侧边栏进行交互,而将与小工具的交互,委托给侧边栏。
😘 侧边栏接口
在进行了上述的分析之后,与相关同事进行沟通,发现侧边栏确实提供了这样的能力(庆幸),并且定义暴露了完善的接口和数据结构。因此,Note可以直接接入侧边栏的接口,并复用侧边栏的该能力。
接口定义
侧边栏对外暴露的接口是以广播的形式进行的,调用如下:
数据结构定义
侧边栏会把当前系统支持的小工具信息进行json结构化,并放到
all_tools_app_config.json 文件中,其数据结构定义如下:根据上面的json格式,定义对应的kotlin数据类:
接口数据读取
对于该json文件,其完整的读取方法如下:
🙈 接入状态定义
由于小工具的信息来源与Note中其他工具的来源不一样(前者是通过读取解析外部json文件,后者是Note内部定义的数据信息),且工具栏已经有了一定的封装行为,无法在原先的基础上,直接添加json数据来源的格式,所以为了尽量减少工具栏业务层逻辑的修改,这里需要对小工具操作做一些封装和状态定义,以供工具栏调用
事件、状态定义
为了减少工具栏的调用难度和复杂度,小工具操作只对外暴露一个方法,并通过传入不同意图参数,触发内部执行不同逻辑,具体的事件定义如下
同时,上面的事件主要用于定义工具栏需要向小工具操作类传递的意图,是从上到下的;而对于小工具向上层的状态传递,则需要定义状态,具体的状态定义如下:
定义了状态和事件,怎么将其结合起来,如下:
🤪 Note接入工具栏
Note接入的时候,前期按照普通工具的接入方式,添加入口即可,这里只记录接入小工具的差异点
同步侧边栏命名
由于是接入侧边栏的小工具,所以,为了保持一致性,Note里小工具的命名,也要做相应的同步,具体的做法是在Note启动后,对工具栏做UI更新,并读取最新的json文件,更新到工具栏中
可见性过滤
小工具在Note中是否可用,主要取决于三个因素:
- Note配置是否支持
- 侧边栏是否含有该小工具的定义
- 系统是否预装了该小工具
具体判断小工具是否在Note中可用的逻辑如下:
😵💫 Bug记录
系统切换语言-多语言适配(内存泄露)
由于工具栏中小工具的命名,已经适配成从侧边栏的json文件解析,所以,在系统语言切换的时候,需要再次去解析最新的json,并更新到工具栏中显示。
根据代码逻辑,理论上,在系统切换语言时,该对象会被销毁,并重新读取json信息
- 现象一:但是实际上,并没有生效,通过log日志打印,发现哪怕是重新应用,也没有走重新解析json文件的逻辑,但是重启却会重新读取。且通过hash打印,发现重启后,对象还是同一个。
- 猜测:内存泄露,因为只有内存泄露,才会导致对象的生命周期超过应用本身的生命周期
- 发现问题:
- 从内存泄露的角度出发,依次排查内部是否持有了长生命周期的对象
- 最后发现,内部持有的对象基本都是内部对象,只有一个异常
packageManager - 结论:
- PackageManager对象的生命周期,比应用还长,应用中,不要直接持有其引用
- 现象二:解决了上述内存泄露后,发现应用重启后,确实会重新读取json文件了,但是系统切换语言时,还是没有及时重新读取json信息
- 猜测:对象生命周期不对,因为按照逻辑,这个小工具读取的对象生命周期应该是跟随主线程的,而不是跟随应用进程的的(系统切换语言时,线程重建,进程不重建)
- 发现问题:
- 对于json信息的对象,是一个静态单例,而单例的生命周期,是随应用进程的。
- 解决:
启动耗时
- 问题:由于需要去读取解析小工具的整个json文件,实测在不同平台上,会带来90~150ms的启动延迟,且对于没有引入该需求的渠道,也会引入这个启动延迟
- 预期:只在有该需求的客户渠道,读取解析json文件,避免引入全平台的延迟
- 分析:
- 从解析json的代码处,添加日志打印出其调用栈
- 根据上面的调用栈,往上追终,最终发现是在工具栏处,有读取json文件,进行多语言适配的逻辑,从而引入了耗时
- 解决:
- 根据是否开启了小工具的配置,决定是否进行读取json信息
- 又因为在工具栏中,会先根据小工具的配置,先对按钮做可见性变动
- 所以,只需要在读取json之前,先判断对应的小工具入口按钮的可见性,即可作为判断的条件
🥺 UML描述
PlantUML语法:
🥳 成长
- packageManager生命周期非常长,由系统控制,应用不应该持有其引用,避免内存泄露
- 静态单例对象的生命周期,是对标应用进程的;而系统语言切换等引发config change的情况,是不会导致应用进程重建的。
- Author:CoderWdd
- URL:https://www.wuinsights.top//article/2ceba0f8-5624-4708-a1f9-30c8036ae67e
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts