IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Kotlin中 Handler 移除 Runnable 无效 -> 正文阅读

[移动开发]Kotlin中 Handler 移除 Runnable 无效

前端时间在做听书功能的时候,遇到了一个问题,Handler 移除 Runnable 无效。 当时的场景是这样的:

代码是Kotlin,在启动播放的时候,延迟800毫米使用Handler发送一个消息,收到消息后,展示loading。如果在800毫秒之内就已经开始播放了,则移除消息,不会展示loading。但是在实际操作过程中发现消息移除不生效,loading还是会展示。下面通过一个例子来探究其中的原因。


//定义handler
val handler: Handler = object : Handler() {

    override fun handleMessage(msg: Message?) {
        super.handleMessage(msg)
    }
}

//注释1处,定义发送的延迟消息,用来展示loading,注意这是一个lambda表达式,并没有显式的声明类型
val showDialogRunnable = {
    Log.i(TAG, "在runnable里面展示弹窗")
    showLoading()
}

注释1处,定义发送的延迟消息,用来展示loading,注意这是一个lambda表达式,并没有显式的声明类型。

fun onClick(v: View) {
    when (v.id) {
        R.id.btn_send_msg -> {
            //点击按钮后,延迟5秒发送消息展示loading
            Log.i(TAG, "onClick: 发送延迟消息")
            handler.postDelayed(showDialogRunnable, 5000)
        }
        R.id.btn_remove_msg -> {
            //在5秒之内移除消息,让loading展示不出来
            Log.i(TAG, "onClick: 移除消息")
            handler.removeCallbacks(showDialogRunnable)
        }
    }
}

结果发现loading还是展示出来了。这是什么原因呢?我们看一下Kotlin反编译出来的java代码。

定义的 showDialogRunnable 对象,可以看到其类型是 Function0 类型,并不是Runnable。

@NotNull
private final Function0 showDialogRunnable = (Function0)(new Function0() {
    // $FF: synthetic method
    // $FF: bridge method
    public Object invoke() {
        this.invoke();
        return Unit.INSTANCE;
    }
    public final void invoke() {
        Log.i("TestFuncActivity", "在runnable里面展示弹窗");
        TestFuncActivity.this.showLoading();
    }
});

注意: 这就是问题的根本所在,我们本来期望的定义的是 Runnable 类型,结果并不是。

public final void onClick(@NotNull View v) {
    Intrinsics.checkNotNullParameter(v, "v");
    Handler var10000;
    Object var10001;
    Object var2;
    switch(v.getId()) {
        case 1000028:
            Log.i("TestFuncActivity", "onClick: 发送延迟消息");
            var10000 = this.handler;
            //注释1处,获取 showDialogRunnable 对象
            var10001 = this.showDialogRunnable;
            if(var10001 != null) {
                var2 = var10001;
                //注释2处,利用 showDialogRunnable 对象创建了一个新对象 一个 TestFuncActivity$sam$java_lang_Runnable$0 对象。
                var10001 = new TestFuncActivity$sam$java_lang_Runnable$0((Function0) var2);
            }
            //注释3处,将包装后的对象传递给Handler的 postDelayed 方法。
            var10000.postDelayed((Runnable) var10001, 5000 L);
            break;
        case 1000172:
            Log.i("TestFuncActivity", "onClick: 移除消息");
            var10000 = this.handler;
            var10001 = this.showDialogRunnable;
            if(var10001 != null) {
                var2 = var10001;
                //注释4处,这里有重新 new 了一个  TestFuncActivity$sam$java_lang_Runnable$0 对象。
                var10001 = new TestFuncActivity$sam$java_lang_Runnable$0((Function0) var2);
            }
            var10000.removeCallbacks((Runnable) var10001);
    }
}

注释2处,利用 showDialogRunnable 对象创建了一个新对象 一个 TestFuncActivity s a m sam samjava_lang_Runnable$0 对象。

TestFuncActivity s a m sam samjava_lang_Runnable$0 这个类是什么东西呢,其实是继承了 Runnable 的一个类。

final class TestFuncActivity$sam$java_lang_Runnable$0 implements Runnable {
    // $FF: synthetic field
    private final Function0
    function;
    TestFuncActivity$sam$java_lang_Runnable$0(Function0 var1) {
            this.function = var1;
        }
        // $FF: synthetic method
    public final void run() {
        Intrinsics.checkNotNullExpressionValue(this.function.invoke(), "invoke(...)");
    }
}

//注释4处,这里有重新 new 了一个 TestFuncActivity s a m sam samjava_lang_Runnable$0 对象。

通过注释2处和注释4处,我们知道了 postDelay 的对象 和 removeCallbacks 的对象是两个不同的对象,所以移除不起作用。

解决方法 : 显式使用Runnable

val showDialogRunnable: Runnable = Runnable {
    Log.i(TAG, "在runnable里面展示弹窗")
    showLoading()
}

我们看下反编译出来的代码,这个时候就是一个 Runnable 对象。

 @NotNull
 private final Runnable showDialogRunnable = (Runnable)(new Runnable() {
     public final void run() {
         Log.i("TestFuncActivity", "在runnable里面展示弹窗");
         TestFuncActivity.this.showLoading();
     }
 });
public final void onClick(@NotNull View v) {
    Intrinsics.checkNotNullParameter(v, "v");
    switch(v.getId()) {
        case 1000028:
            Log.i("TestFuncActivity", "onClick: 发送延迟消息");
            //注释1处, postDelayed showDialogRunnable
            this.handler.postDelayed(this.showDialogRunnable, 5000 L);
            break;
        case 1000172:
            Log.i("TestFuncActivity", "onClick: 移除消息");
            //注释2处, removeCallbacks showDialogRunnable
            this.handler.removeCallbacks(this.showDialogRunnable);
    }
}

注释1处, postDelayed showDialogRunnable。
注释2处, removeCallbacks showDialogRunnable。

现在 postDelayed 和 removeCallbacks 的就是同一个对象了,可以正常移除。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-09-30 01:04:20  更:2022-09-30 01:04:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/29 7:59:45-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码