【Android】记录一次换肤插件问题排查

记录一次换肤插件问题排查

PS:出现的问题已经修复并发布至Github:https://github.com/LittleFogCat/skin-support

问题出现

在项目中遇到了闪退的情况。

经过排查,发现跟第三方换肤插件 Android-skin-support 有关。只要当前触发换肤,则会偶然出现问题。

在经过多番搜索之后,了解到该 bug 是由于该第三方库新版本的 AndroidX 不兼容造成的。而该作者早已停止维护,所以只能另寻他法了。

摆在面前的有这么几条路:

  1. 网上搜索解决方案;
  2. 自行排查并修改其源码;
  3. 使用其他换肤插件;
  4. 不做换肤功能;

以上几个方案,优先度依次递减。

探索解决方案

1. 降版本

在 Github 该项目的 issue 中,发现了与我们遇到的相同问题:issue470

可以得出结论:

  • 的确是该第三方库与新版本 AndroidX 不兼容造成的问题;
  • 该作者停止维护;
  • 可以通过强制降低 AndroidX 版本来解决问题;

那么,摆在面前最简单的方式就是降低 AndroidX 版本了。当然,这只是权益之举,弃车保帅之法。

在降低了 AndroidX 版本之后,应用的确不会闪退了。但是问题是,应用并没有换肤,也就是说这个功能并没有实现。

由于第三方库无法调试,如果要实现功能,要么调试修改其代码,要么换一个换肤插件。前者需要阅读源码,耗费时间颇多,且不一定成功,有可能竹篮打水一场空;后者成本较高,如果换新的框架,不仅需要学习成本,重新开发模块,且服务器也需要重新部署。所以决定先尝试调试、修改其源码。

2. 排查问题

闪退问题

下载源码到本地,首先排查的是闪退的问题。

由于现在已经可以调试,所以将 AndroidX 升到正常版本。

经过排查,发现是该换肤插件引用的系统资源,在新版本的 AndroidX 中已被移除,所以出现了无法找到资源的 bug,造成闪退。

于是在经过移除、更换了对应资源之后,闪退的问题便修复了。

换肤不成功问题

换肤不成功这个问题,耗费了许多时间。由于不清楚该框架原理,像这种不出现闪退的问题很难跟踪。

在跟踪了 loadSkin 方法之后,发现其并没有直接进行换肤操作,而是起了一个 AsyncTask,加载对应的 skin 文件,并通过 setupSkin 方法将 SkinCompatResources 字段赋值。也就是说, loadSkin 方法只是加载了对应的 skin 文件,并没有执行对应资源的实时替换。这一点让我想到了 Android 中的 Animation,其也只是对 View 中的字段进行修改,而实际上的动画效果是靠 Android 的刷新机制来实现的。

这点线索断掉之后,有些没有头绪。在翻看代码的过程中,我发现了一些类的名称:SkinCompatTextViewSkinCompatButtonSkinCompatEditText……如同一道闪电划过,我想起了一些事情。

众所周知,在使用了 AppCompatActivity 的情况下,其中的 TextViewButton 等控件都会被替换成 AppCompatTextViewAppCompatButton 等。这是如何实现的呢?是通过 LayoutInflater.Factory2 来实现的。关于这一点,我之前也写过文章,【Android】全局自定义字体的实现

也就是说,只需要替换掉 LayoutInflate.mFactory2 字段,即可实现偷梁换柱的效果,也就是换肤插件实现的原理。

而为什么换肤插件失效了呢?这是因为其使用的 LayoutInflater.setFactory2 方法来设置的字段,而新版本 Android 对这一块做出了一些调整,具体是什么我也忘记了,不过最终的结果就是报错。虽然它给报错 catch 住了,但也造成了换肤功能的失效。

解决方案我在 【Android】全局自定义字体的实现 中也写了,那就是通过反射替代对应方法的调用,直接修改字段的值,就不赘述了。

在经过测试之后,我懵了。居然爆出 java.lang.NoSuchFieldException: mFactory 的错误。原来新版本 Android 中,将 mFactorymFactory2 字段保护起来了。我靠。又过了好一阵思索,我发现测试机的版本只有 Android 8,并不是新版本……原来是我自己把 getDeclaredField 写成了 getField……

改好之后,替换成功了!虽然还是没有成功换肤……但是离成功又近了一步。

最后,继续排查,发现没有成功换肤的原因是设置背景图片的对象是 contentFrame,即除去 ActionBar 之后 Activity 的根布局;而众所周知,每个 Android 初学者都知道,contentFrame 的类型是 FrameLayout。然而,实际上,它的类型却是 ContentFrameLayout!这个可能是新版本的 Android 中的实现。不管怎么说,这个原因导致了换肤插件没有做适配。自己手动添上对应类的适配,终于解决了。

完结!

后记

后来又遇到了切换 Fragment 不显示的问题,最终排查结果是因为 Fragment 的容器类型是 FragmentContainerView,不是换肤插件支持的控件,所以其宽高变成 0 了(?)至于为什么会这样,时间太晚无力再看了。把控件类型换成 FrameLayout,问题解决。

总的来说,这玩意儿能不用就不用吧……

后记2

我把原代码修改了一下,修复了一些问题,并发布到了Github,有需要的可以自取:https://github.com/LittleFogCat/skin-support

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343