大家好,又见面了,我是你们的朋友全栈君。
一、屏幕适配
你可能会问 “都 2021 年了还折腾屏幕适配?直接用 dp 单位适配不好吗?”, 确实,如果公司的 UI 设计师、产品经理以及老板,能明白为什么一套 UI 在不同设备上显现出来的一些差异并不是 bug 时,开发者直接用 dp 单位配合一些布局技巧来进行适配是可以的,但是,实现多数情况下并不是如此美好,他们更希望看到的是 UI 在不同屏幕上,仅仅只是缩放的区别,为了满足这种要求,应用第三方屏幕适配方案就非常有必要了。根据在网上查到的比较好的原生屏幕适配方案有两种:
- smallestWidth 限定符适配方案
- 今日头条屏幕适配方案
两者的原理,以及优缺点这里不废话,有兴趣的可通过下方链接了解:
- smallestWidth 限定符适配方案:https://juejin.cn/post/6844903681524006925
- 今日头条屏幕适配方案:https://juejin.cn/post/6844903661819133960
考虑到 apk 体积包大小问题,最终还是选择了 AndroidAutoSize
,同时项目中有使用到插件化框架 RePlugin
,需要在插件中集成 AndroidAutoSize
,然而网上又几乎没有相关的集成踩坑资料,于是便有了本篇文章~
二、问题与解决方案
AndroidAutoSize
的使用说明及已知问题汇总请访问以下链接查看:
- https://github.com/JessYanCoding/AndroidAutoSize
- https://github.com/JessYanCoding/AndroidAutoSize/issues/13
按作者的集成步骤,在 app 作为单品运行时是没有任何问题的,但是,如果你项目中使用了 RePlugin,一旦 app 作为插件运行中,你就会发现,一点用都没有!!!
注意:本文基于关闭常驻进程的前提完成的论证及测试,即:
persistentEnable = false
。
1、框架初始化
不可否认,AndroidAutoSize
的框架设计很优秀,利用 ContentProvider
实现框架自动初始化工作,然而,这种”黑科技”在个别情况下不好使,比如有些魔改 ROM,还有就是作为 RePlugin 插件的时候,所以,AndroidAutoSize
没起作用的一方面原因是框架未能正常初始化,插件 AndroidManifest.xml 中声明的 ContentProvider
并不会自动被执行创建,也就是 InitProvider
没被执行到,好在该库提供了手动初始化的方式:
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// 手动直接执行 AutoSizeConfig#init()
AutoSize.checkAndInit(this)
// 通过启动InitProvider,再由InitProvider执行 AutoSizeConfig#init()
// AutoSize.initCompatMultiProcess(this)
}
}
AutoSize.checkAndInit(this)
亲测有效,AutoSize.initCompatMultiProcess(this)
没有测试过,理论上也是可以的,但大可不必。
通过上面的代码就可以解决 AndroidAutoSize
的初始化问题。另外,如果你担心 app 作为单品时,AutoSizeConfig#init()
会被 AutoSize.checkAndInit(this)
和 InitProvider
执行多次的话,你可以选择把 InitProvider
移除掉:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
<application ... android:name=".MyApplication">
<provider tools:node="remove" android:name="me.jessyan.autosize.InitProvider" android:exported="false" android:multiprocess="true" android:authorities="${your application id}.autosize-init-provider" />
</application>
</manifest>
关键点是 tools:node="remove"
,可以把 aar 中的 AndroidManifest.xml 声明好的组件移除。此处的 ${your application id}
需要根据你当前 app 的 appid 来修改,不知道怎么改的话,可以先正常打个包,再反编译看看 AndroidManifest.xml 中原来的 InitProvider
声明是怎样的就明白了。
其实并不需要担心
AutoSizeConfig#init()
会被执行多次的问题,框架肯定有做好防护措施的,但如果你很严谨,不想有意外情况发生的话,强烈建议把InitProvider
移除,这样的话,不管是单品还是插件,初始化逻辑都将是一样的。
2、启动屏幕适配功能
解决完框架初始化的问题,现在 AndroidAutoSize
还是无法起作用的。通过 AndroidAutoSize
源码可以得知,框架会给 Application 注册一个 ActivityLifecycleCallbacks
,用于执行各个 Activity 初始化时的适配工作,然后,当 app 作为插件时这个 ActivityLifecycleCallbacks
是不会回调的-_-
- 原因:插件的 Application 无法正常注册
ActivityLifecycleCallbacks
- 解决方案:用宿主的 Application 注册
ActivityLifecycleCallbacks
怎么用宿主的 Application 注册 ActivityLifecycleCallbacks
呢?Easy,在初始化 AndroidAutoSize
的时候用宿主的 Application 即可:
// if (RePlugin.getHostContext() != null) { // 插件
// AutoSize.checkAndInit(RePlugin.getHostContext().applicationContext as Application)
// } else { // 单品
// AutoSize.checkAndInit(this)
// }
// 简洁写法:
AutoSize.checkAndInit(RePlugin.getHostContext()?.applicationContext as? Application ?: this)
好了,到这里 AndroidAutoSize
就起作用了。
这个
ActivityLifecycleCallbacks
(也就是ActivityLifecycleCallbacksImpl
) 相当重要,它生效了,CancelAdapt
和CustomAdapt
才能正常使用。
3、指定设计图尺寸
现在框架初始化,以及屏幕适配功能都已经没有问题了,接下来就是配置工作,默认情况下,AndroidAutoSize
会读取开发者在 AndroidManifest.xml 中预先填写好的 meta 设计图尺寸,用于计算 DisplayMetrics#density
,然而当 app 作为插件时,你会发现这个配置也是无效的。
- 原因:框架中通过 context 拿到的是宿主的 AndroidManifest.xml 信息,因为上面
AutoSize#checkAndInit()
传入的是宿主的 Application - 解决方案:由于
AutoSizeConfig#getMetaData(final Context context)
是私有方法,所以,你有 2 种选择:- 反射调用
AutoSizeConfig#getMetaData()
并传入插件的 Application - 改为代码配置的方式,给
AutoSizeConfig
直接指定设计图尺寸
- 反射调用
别跟我说什么在宿主的 AndroidManifest.xml 中配置设计图尺寸,太 low 了-_-
怎么简单怎么来,这里就通过代码方式给 AutoSizeConfig
直接指定设计图尺寸:
AutoSize.checkAndInit(RePlugin.getHostContext()?.applicationContext as? Application ?: this)
// 注意:一定要在框架初始化之后再进行配置,否则框架内部拿不到正确的设计图尺寸(会被 AutoSizeConfig#init() 重置)
AutoSizeConfig.getInstance()
// 手动指定设计图尺寸,不读取清单文件
.setDesignWidthInDp(1280)
.setDesignHeightInDp(720)
// 设置使用冷门尺寸单位作为副单位
.unitsManager
.setSupportDP(false)
.setSupportSP(false)
.setSupportSubunits(Subunits.MM)
至此,AndroidAutoSize
无论是单品还是插件都能正常运作了,Nice~
三、其他
这里就已经和 RePlugin 的坑没有关系了,只是记录一些 AndroidAutoSize
的使用问题。
1、重写 Activity#getResources()
导致 CancelAdapt
和 CustomAdapt
失效
原因是在 getResources()方法中没有判断当前 Activity 是否有实现 CancelAdapt
和 CustomAdapt
,一股脑全部适配导致的,只需要做个判断就好了:
abstract class BaseActivity : AppCompatActivity() {
...
override fun getResources(): Resources {
when (this) {
is CancelAdapt -> {
AutoSizeCompat.cancelAdapt(super.getResources())
}
is CustomAdapt -> {
AutoSizeCompat.autoConvertDensityOfCustomAdapt(super.getResources(), this)
}
else -> {
//需要升级到 v1.1.2 及以上版本才能使用 AutoSizeCompat
AutoSizeCompat.autoConvertDensityOfGlobal((super.getResources())) //如果没有自定义需求用这个方法
// AutoSizeCompat.autoConvertDensity((super.getResources()), 667f, false)//如果有自定义需求就用这个方法
}
}
return super.getResources()
}
}
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/134862.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...