其他适配
多任务窗口中的界面高斯模糊
LayoutParams.FLAG_SECURE
最近任务列表窗口不展示内容,该 window 也不支持截屏
1
window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE)
广播监听多任务键与 Home 键
- 监听多任务按键,contentView 设置高斯模糊,onResume 时恢复
- 如果按 home,再按多任务按键,就不支持了
手机系统厂商
- 手机系统厂商有个白名单,支付相关的就给你高斯模糊
Kotlin Android Extension AGP8.0 移除
synthetic(和 findViewById 说再见)
我们不需要使用 findViewById 来获取控件,只需要使用控件的 id 就可以操作控件的相关方法。
原理:
在第一次使用控件的时候,在缓存集合中进行查找,有就直接使用,没有就通过 findViewById 进行查找,并添加到缓存集合中。其还提供了 _$_clearFindViewByIdCache()
方法用于清除缓存,在我们想要彻底替换界面控件时可以使用到。
Activity
Activity 在 onDestroy 时不会调用 _$_clearFindViewByIdCache()
,导致在 onDestoy 后控件也还是可以引用,如果需要清理需要手动调用 clearFindViewByIdCache
Fragment
和 Activity 的唯一区别就是在 onDestroyView()
方法中调用了 _$_clearFindViewByIdCache()
,来清楚缓存,所以我们不用担心在 View 销毁的时候,缓存不能及时释放的问题。
ViewHolder 中如何使用 Extansions
kotlin1.1.4
版本的 kotlin-android-extensions 增强功能,需要在 build.gradle 中开启实验性标志:
1
2
3
androidExtensions {
experimental = true
}
接下来我们就可以试着去编写 ViewHolder 了,只需要实现 LayoutContainer 接口,该接口只提供了一个 containerView,用于存储视图
ViewHolder 初始化的时候,将传进来的 view 存储在 containerView 变量中,和 Activity 的 $findCachedViewById 一样,ViewHolder 中的使用的是 containerView.findViewById,即通过传进来的 View 进行 View.findViewById,从而获取控件。
使用 ContainerOptions 修改 View 的缓存类型
默认 View 的缓存是是使用的 HashMap 来做的,官方提供了注解的方式来进行修改:
1
2
3
4
@ContainerOptions(CacheImplementation.SPARSE_ARRAY)
class TestActivity : AppCompatActivity() {
// ...
}
CacheImplementation 提供了三种方式:
1
2
3
4
5
6
7
8
9
10
11
12
public enum class CacheImplementation {
SPARSE_ARRAY,
HASH_MAP,
NO_CACHE;
public val hasCache: Boolean
get() = this != NO_CACHE
companion object {
val DEFAULT = HASH_MAP
}
}
当然某些时候你只在 Activity 加载的时候,使用一次控件,那么就可以选择 NO_CACHE
。
过时适配
- 要再见了吗,Kotlin Android Extension
- https://github.com/kanyun-inc/Kace
- kotlin-android-extensions 插件将被正式移除,如何无缝迁移?
特殊 ROM 兼容适配
oppo 和 vivo 手机 AppCompat 主题问题
报错
- bugly 上报:
1
2
3
4
#1339847 java.lang.UnsupportedOperationException
Failed to resolve attribute at index 13: TypedValue{t=0x2/d=0x7f0404c2 a=-1}
android.content.res.TypedArray.getDrawable(TypedArray.java:925)
- logcat 日志:
1
ThemeUtils: View class qsbk.app.message.widget.CircleNotifyView is an AppCompat widget that can only be used with a Theme.AppCompat theme (or descendant).
- 链接:
分析
- CircleNotifyView 实现:
1
class CircleNotifyView : AppCompatTextView { }
remix 主题情况,values
、values-v11
、values-14
下都有 AppBaseTheme 主题,values-v21 没有:
- values 目录下的 styles.xml
1
2
3
4
5
6
7
<style name="AppBaseTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!--
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
-->
</style>
- values-v11 目录下的 styles.xml
1
2
3
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.NoActionBar">
<!-- API 11 theme customizations can go here. -->
</style>
- values-v14 目录下是 styles.xml
1
2
3
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.NoActionBar">
<!-- API 14 theme customizations can go here. -->
</style>
再看下手机系统和型号分布,主要集中在 OV 手机的 7.x 版本上:
猜测是 ov 手机系统,加载主题机制有问题,如果存在非 values 目录下 AppBaseTheme
,如果该 values-xxx
目录存在,就会去对应目录加载,默认不会去 values 下加载主题,类似 so 的加载机制
解决(猜测,未验证)
在 values-v21 也加上 AppBaseTheme 主题:
1
2
<style name="AppBaseTheme" parent="Theme.AppCompat.Light.NoActionBar">
</style>
从 launcher 点击应用图标重复打开开屏页的问题
在你的 android.intent.category.LAUNCHER
的 Activity 增加下面代码:
1
2
3
4
5
6
7
8
9
10
11
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 启动后点击回退到桌面再次点击应用图标重复启动的问题
if (!isTaskRoot
&& intent.hasCategory(Intent.CATEGORY_LAUNCHER)
&& intent.action != null
&& intent.action.equals(Intent.ACTION_MAIN)) {
finish()
return
}
}