升级 Android 目标版本到 31(S) 居然这么多坑_android 31

对于 exported 属性,你可以查看谷歌官方文档的详细解释:android:exported

适配这个属性并不难,只需要在 manifest 中明确指定每个组件的 exported 属性即可。一般来说,遵循如下原则:如果组件中使用了 intent-filter 等属性,那么它大概率是需要对外暴露的,此时需要将 exported 属性直为 true,其他情况下置为 false 即可。

对于引用的三方类库中的 xml 属性也可以通过覆写声明方式增加 exported 以兼容处理,

<activity android:name="com.squareup.leakcanary.internal.DisplayLeakActivity"
    android:exported="false"/>

3、PendingIntent 的变动

这是一个隐藏的变动,非常坑又不像 exported 属性那样容易被察觉。这边变动主要是要求开发者指定在创建 PendingIntent 的时候传入的 flags 参数的可变性。

这可以通过在之前的 flags 基础上增加 FLAG_MUTABLEFLAG_IMMUTABLE 两个属性来完成。比如,之前我的 flags 是,PendingIntent.FLAG_CANCEL_CURRENT,当我想将其修改为不可变的时候,就可以使用如下方式进行修改:

val flags = PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE

它可能是需要改动最多的一个变动,根据我在项目中修改的情况来看,以下几个场景需要排查:

  • 桌面小控件 Appwidget
  • 通知 Notification
  • 桌面快捷方式 Shortcut

同时从几个方向来检索项目中需要改动的地方:

  • 直接检索 PendingIntent 的 flags 的调用,比如 FLAG_ONE_SHOT, FLAG_NO_CREATE, FLAG_CANCEL_CURRENTFLAG_UPDATE_CURRENT 等,建议查看源码之后进行检索
  • PendingIntent 的静态方法工厂,比如 PendingIntent.getBroadcast()PendingIntent.getActivity() 等。因为,获取 PendingIntent 的时候需要指定 flags 参数。

那么,另一个问题来了,究竟什么时候该选择 FLAG_MUTABLE,什么时候该选择 FLAG_IMMUTABLE 呢?

它的注释是这么说的,

Flag indicating that the created PendingIntent should be immutable. This means that the additional intent argument passed to the send methods to fill in unpopulated properties of this intent will be ignored. FLAG_IMMUTABLE only limits the ability to alter the semantics of the intent that is sent by send by the invoker of send. The creator of the PendingIntent can always update the PendingIntent itself via FLAG_UPDATE_CURRENT.

也就是说,FLAG_IMMUTABLE 的“不可变”指的是,当 PendingIntent 设置了 flags 为“不可变”之后,调用它的 send 方法时传入的 Intent 将会被忽略。

这里举一个具体的场景,比如在列表类的 Appwidget 里,我们会使用 PendingIntent 设置列表的某一项的点击事件。考虑到列表量比较大,为每一个列表条目都声明一个 PendingIntent 显然开销太大。所以,Android 的处理机制是,

val views = RemoteViews(context.packageName, R.layout.layout_appwidget_note_list)
val i = Intent(context, MainActivity::class.java)
i.action = ACTION_APPWIDGET_NOTE_CLICK
val pi = PendingIntent.getActivity(context, 0, i, FLAG_CANCEL_CURRENT_MUTABLE)
views.setPendingIntentTemplate(R.id.lv, pi)

如上所示,首先定一个一个 PendingIntent,并调用 RemoteViews 的 setPendingIntentTemplate 方法传入,作为一个模版。然后在 RemoteViewsFactory 的 getViewAt 方法中为每个列表项设置点击时的 Intent,

val row = RemoteViews(context.packageName, R.layout.item_appwidget_note)
val i = Intent().putExtras(extras)
row.setOnClickFillInIntent(R.id.root, i)

当用户触发了点击事件的时候,系统会在调用 PendingIntent 的 send 方法时将 Intent 传入并唤起组件。此时,如果我们将 PendingIntent 的 flags 设置为 FLAG_IMMUTABLE,那么这里发送时传入的 Intent 参数将被忽略,因此可能导致虽然唤起了其他组件,但是参数丢失的情况。而对于那种,声明 PendingIntent 时就传入了 Intent 的时候,一般来说不需要设置为 FLAG_MUTABLE 的。

以上是 PendingIntent 的改动,刚好在我的项目里两种情况都有遇到,所以详细分析了一下。

4、构建项目 JDK 需要升级

当将项目的 targetSdkVersion 升级到了 31 之后,构建项目的时候可能会遇到如下异常,

当然你也可能不会遇到这个问题。那主要的原因是,你的 Android Studio 里 Gradle 构建时用到的版本已经是 Java 11 的了。可以通过 Preference->Build->Gradle 查看当前 Android Studio 中使用的 JDK 版本,

Gradle JDK 处修改构建时用的 JDK 版本即可。

以上是针对 Android Studio 构建时的情况。但当我们使用脚本或者命令行构建项目的时候需要用到的就不是 Android Studio 的 JDK 版本了。此时,可以通过 java --version 查看环境变量中配置的 JDK 版本。

我们不能直接修改环境变量中的 JDK 版本解决上述编译问题。因为毕竟除了开发,我们可能还有很多其他应用在使用 JDK 环境。此时,我们可以通过 Gradle 构建时的命令来指定构建时使用的 JDK。

gradlew -Dorg.gradle.java.home=你的 JDK 路径

对于打包脚本的修改我也更新到了项目 autopackage 中。

结语

网上高级工程师面试相关文章鱼龙混杂,要么一堆内容,要么内容质量太浅, 鉴于此我整理了上述安卓开发高级工程师面试题以及答案。希望帮助大家顺利进阶为高级工程师。
目前我就职于某大厂安卓高级工程师职位,在当下大环境下也想为安卓工程师出一份力,通过我的技术经验整理了面试经常问的题,答案部分是一篇文章或者几篇文章,都是我认真看过并且觉得不错才整理出来。

大家知道高级工程师不会像刚入门那样被问的问题一句话两句话就能表述清楚,所以我通过过滤好文章来帮助大家理解。

1307页字节跳动Android面试真题解析火爆全网,完整版开放下载

现在都说互联网寒冬,其实只要自身技术能力够强,咱们就不怕!我这边专门针对Android开发工程师整理了一套【Android进阶学习视频】、【全套Android面试秘籍】、【Android知识点PDF】。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

里获取](https://bbs.csdn.net/topics/618156601)**

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值