谷歌的bug:当 CompileSdk 33 遇上Kotlin

最近项目里compose 要升级到1.3, 要求compile sdk 也要到33版本,大家都知道 一般情况下,我们修改compilesdk 都不会有什么问题,最多就是一些api的适配,编译不过啥的, 但是不会引发线上故障,但是这里要注意了target sdk 的修改 就要复杂的多了, 这里不多说,只介绍一下 我碰到的一个compilesdk 33的问题

在Compile sdk 33版本中,这个手势监听的接口 代码发生了一些变化:

在这些接口方法说 参数前面加上了一个NonNull的 注解,这个注解的意思就是 告诉开发者 这个参数不可能为空

注意了 在<=32的版本中 这个注解是没有的

对于java的开发者来说,这个影响微乎其微,但是如果你跟我一样是kotlin的开发者就要倒霉了,

因为在<=32的时候 你继承这个接口的时候 会提示你参数要定义成可空的

但是当你升级到33的sdk的时候,你就会发现编译不过了

为啥?

因为33的sdk 前面说过了,方法前面有了 不可空的注解了

要让他编译过很简单 我们只要把? 去掉即可

到这里还没结束,最坑的地方来了, 虽然你能编译过,但是在运行时,有可能会发生crash

为啥? 熟悉kotlin的人就知道了,当你定义一个参数为不可空的类型的时候,你如果传了一个null给这个参数,他就会报这个crash了,这种情况常见于 java代码调用kotlin代码的时候 这是kotlin编译器的魔法,有兴趣的可以自己反编译看一下字节码,实际上,当你定义一个变量为不可空的时候,如果传值给他 他就会校验这个值 是不是为null 为null 则直接抛异常

搞清楚问题所在以后 就得想想怎么解决了,目前的情况就是 如果不改,就编译不过,改了 在运行时会crash

另外: 这里有个链接,可以看下该问题的讨论,目前状态是显示 谷歌承认了该bug,看状态显示fixed,但是不知道为什么 还没有推送最新的33 sdk issueTracker

实际上解决这个问题的方法有很多,

方法1: 这个接口的实现 我们不用kotlin写,用java写,即可 这个方案最简单,但是不太优雅

方法2: 魔改下android sdk 33版本的jar包,把注解去掉 这个方案也可以,但是有点麻烦

方法3: asm 字节码修改,把那个校验参数为null 就抛异常的代码删了就行了。 杀鸡焉用牛刀

方法4: 写一个delegate 即可,以后都用这个代理类去做监听, 这个方法我认为是最简单的,一劳永逸,而且成本极低


import android.content.Context;
import android.os.Handler;
import android.view.GestureDetector;
import android.view.MotionEvent;

import androidx.annotation.Nullable;

/**
 * 在compile sdk 33 中 修复google的一个注解bug,该bug 会导致 要么kotlin代码编译失败
 * 要么运行时crash,这里用代理模式 简单的规避此问题即可
 *
 */
public class GestureDetectorDelegate extends GestureDetector {
    /**
     * @param listener
     * @param handler
     * @deprecated
     */
    public GestureDetectorDelegate(OnGestureListener listener, Handler handler) {
        super(listener, handler);
    }

    /**
     * @param listener
     * @deprecated
     */
    public GestureDetectorDelegate(OnGestureListener listener) {
        super(listener);
    }

    public GestureDetectorDelegate(Context context, OnGestureListenerDelegate listener) {
        super(context, listener);
    }

    public GestureDetectorDelegate(Context context, OnGestureListener listener, Handler handler) {
        super(context, listener, handler);
    }

    public GestureDetectorDelegate(Context context, OnGestureListener listener, Handler handler, boolean unused) {
        super(context, listener, handler, unused);
    }

    /**
     * 主要修改点就是在这里了,复写这些方法 标记这些参数为可空的即可
     */
    public interface OnGestureListenerDelegate extends OnGestureListener {
        boolean onDown(@Nullable  MotionEvent e);

        void onShowPress(@Nullable   MotionEvent e);

        boolean onSingleTapUp(@Nullable   MotionEvent e);

        boolean onScroll(@Nullable  MotionEvent e1, @Nullable  MotionEvent e2, float distanceX, float distanceY);

        void onLongPress(@Nullable  MotionEvent e);

        boolean onFling(@Nullable  MotionEvent e1, @Nullable  MotionEvent e2, float velocityX, float velocityY);
    }
}

方案5: 利用proguard混淆的配置规则

其实所谓的抛异常,就是kotlin在编译的时候 手动帮我们增加了判断是否null 然后抛异常的方法

那我们实际上最简单的方案就是 利用混淆的规则,在release包构建的时候 把这个代码去掉就可以了

-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
    public static void check*(...);
}

作者:vivo祁同伟
链接:https://juejin.cn/post/7174595937724006430

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
在这里插入图片描述
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

全套视频资料:

一、面试合集
在这里插入图片描述
二、源码解析合集

在这里插入图片描述
三、开源框架合集

在这里插入图片描述
欢迎大家一键三连支持,若需要文中资料,直接点击文末CSDN官方认证微信卡片免费领取↓↓↓

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值