安卓TabLayout低版本的兼容性大坑
前段时间我尝试了把可可拼音输入法移植到9键手机上,比如多亲的F22
以及日本一些像各种Softbank
定制机,最低版本降至安卓5.0
版本,除了按键的适配运行方面没有太大问题,后来我在自己的电子纸书上跑了一下,也还不错,具体见可可拼音输入法在QUADERNO上体验。
中秋节回家给外婆的电视装上了我最近刚更新的可可桌面版本,但是发现无法切换默认桌面,系统做了修改,也就是我做的一键启动没法用,估计跟小米的差不多,本来我是想禁用系统桌面的,但是想了一下还是算了了,毕竟这不是测试设备,所以还是想通过输入法来实现这个一键启动应用的功能,因为很多机顶盒还是4.4
版本的,我尝试把可可拼音输入法最低版本降低到安卓4.4
进行测试,但是运行之后发现编辑框一旦激活输入法前台应用整个僵死,跟踪了一下发现是我在软件的符号面板上用到了控件com.google.android.material.tabs.TabLayout
,会直接报错The style on this component requires your app theme to be Theme.AppCompat
,但是在设置界面使用这个控件是正常的,于是我跟踪了一下,发现是ThemeEnforcment.java
在检查上下文主题的时候报错,由于Activity
是继承ContentThemeWrapper
,没有问题,但是输入法创建的Candidates
视图上下文是InputMethodService
,理论上来说它应该使用Application
的主题配置,不应该出现这个问题,但是事与愿违,Google的人在开发TabLayout
组件的时候应该没有对低版本的系统进行过兼容测试,本来我还想通过反射修改一些属性来解决这个问题,但是跟到Resources.java
的obtainStyledAttributes
发现问题最终指向了AssetManager
的applyStyle
,这个是调用native
层的方法,没什么戏了。
// ThemeEnforcment.java
private static void checkTheme(
@NonNull Context context, @NonNull int[] themeAttributes, String themeName) {
if (!isTheme(context, themeAttributes)) {
throw new IllegalArgumentException(
"The style on this component requires your app theme to be "
+ themeName
+ " (or a descendant).");
}
}
// Context.java
public final TypedArray obtainStyledAttributes(
int resid, int[] attrs) throws Resources.NotFoundException {
return getTheme().obtainStyledAttributes(resid, attrs);
}
// Resouces.java
public TypedArray obtainStyledAttributes(int[] attrs) {
int len = attrs.length;
TypedArray array = getCachedStyledAttributes(len);
array.mRsrcs = attrs;
AssetManager.applyStyle(mTheme, 0, 0, 0, attrs,
array.mData, array.mIndices);
return array;
}
解决办法只能是换控件,目前我不想动这一块了,先放弃4.4
版本支持了。