文章

其他适配

其他适配

多任务窗口中的界面高斯模糊

LayoutParams.FLAG_SECURE

最近任务列表窗口不展示内容,该 window 也不支持截屏

1
window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE)

广播监听多任务键与 Home 键

  1. 监听多任务按键,contentView 设置高斯模糊,onResume 时恢复
  2. 如果按 home,再按多任务按键,就不支持了

手机系统厂商

  1. 手机系统厂商有个白名单,支付相关的就给你高斯模糊

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

过时适配

特殊 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 主题情况,valuesvalues-v11values-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 版本上:

image.png

猜测是 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
    }
}

64 位适配

64 位 so 检测

本文由作者按照 CC BY 4.0 进行授权