Android进阶之路Android开发Android开发经验谈

Kotlin Jetpack 实战 | “不为人知”的协程调试技

2020-08-17  本文已影响0人  Android进阶小麦

前言

协程(Coroutines),是个让人又爱又恨的东西。代码写起来是真的,调试起来是真的

本文将介绍 Kotlin 协程的调试技巧,不会涉及太多协程实际内容。所以,不管你有没有协程的基础,都可以看下去,如果有遇到不懂的概念直接忽略即可,后面我会系统讲解。

这篇文章是为我们协程系列打基础的,后面进入我们的协程部分《图解协程》,具体的写作计划大家可以到这里看看:《Kotlin Jetpack 实战:目录》,欢迎提建议。

2. 前期准备

3. 协程 JVM 参数

协程,可以理解为轻量级的线程。协程跟线程的关系,有点像“线程与进程的关系”。

在我们写 Java 并发代码的时候,我们经常会用 Thread.currentThread().name 带打印出当前线程的名字,然后通过日志来查看运行效果。

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
    final int index = i;
    fixedThreadPool.execute(new Runnable() {
        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread().getName() + "index = " + index);
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
}

/*
pool-1-thread-1index = 0
pool-1-thread-3index = 2
pool-1-thread-2index = 1
pool-1-thread-2index = 3
pool-1-thread-3index = 4
*/
复制代码

对于 Kotlin 协程,我们也可以做类似的事情。具体做法是,添加 JVM 参数:-Dkotlinx.coroutines.debug。具体做法如下:

在加上这个参数以后, 我们通过 Thread.currentThread().name,就会自动为我们输出当前协程的名字。

// 这段代码看不懂没关系,忽略即可
// 请直接看后面的输出信息和注释
fun main() {
    runBlocking<Unit> {
        fun log(msg: Any) {
            println("${Thread.currentThread().name} msg=$msg")
        }

        log(1)

        launch {
            val a = 4
            delay(300)
            log(a)
        }
        launch {
            val b = 3
            delay(200)
            log(b)
        }
        launch {
            val c = 2
            delay(100)
            log(c)
        }
    }
}

/*
// 输出:

1个线程   4个协程
 ↓         ↓
main @coroutine#1 msg=1
main @coroutine#4 msg=2
main @coroutine#3 msg=3
main @coroutine#2 msg=4
*/
复制代码

小结

看到这里,也许会有小伙伴说:“我还是搞不懂协程到底是什么,输出一个日志,能说明什么问题呢?”

确实,我在刚学习协程的时候,也有这种苦恼,协程太抽象了,比线程还抽象。线程它起码有一个 Thread.java 的源码给你看,协程呢,没有,Kotlin 编译器将它底层细节都屏蔽了。

那么,有没有更直观的方式来调试协程呢?有的,只是目前国内知道的人应该不多。

前几天我在 Kotlin 官方的博客 中了解到:Kotlin 官方在 1.4 版本中为协程调试增加了许多支持。虽然 Kotlin 1.4 现在还没正式发布,但是我们可以抢先体验它的 RC 版本(Release Candidate Version)。

4. Kotlin 1.4 协程调试

Kotlin 1.3 最让我惊喜的是 Flow,而 Kotlin 1.4 最让我惊喜的则是“协程调试支持”

在 Kotlin 1.4 之前,我一直都是通过 JVM 参数来研究协程的,这种方式并不友好,有的时候为了理解协程的代码,我需要加很多无关的 log。

一起看看 Kotlin 1.4 的变化:

Kotlin 1.4 之前 Kotlin 1.4
断点 断点经常不生效 稳定
单步调试 单步调试经常不生效 稳定
单独的协程调试窗口 不支持 支持
查看协程创建栈 不支持 支持
查看协程调用栈 不支持 支持
协程挂起状态 不支持 支持
协程内存信息 dump 不支持 支持

虽然 Kotlin 1.4 尚未发布,但这并不影响我们提前探索使用 Kotlin 1.4,毕竟早用早享受嘛。

4-1 升级 Kotlin 版本

首先,将 Kotlin 相关的库升级到最新的:1.4-RC

    const val kotlinVersion = "1.4.0-rc"
    const val coroutines = "1.3.8-1.4.0-rc"
复制代码

4-2 Kotlin EAP 渠道

接下来,我们需要升级 IDE 自带的 Kotlin 插件版本:

4-3 协程的断点设置

4-4 协程调试窗口

4-5 协程的调试栈

在上面的调试框中,我们能看到我们的代码当前有三个协程,其中1的位置,代表:corouine2, coroutine3 的状态是 Suspend2的位置,代表corouine4 的状态是 Running3的位置,是该协程的创建栈。

4-6 协程 Dump

由于我们使用的并非正式的版本,Dump 出来的信息还比较少,相信之后官方对协程调试的支持会越来越好。

5. 总结

觉得有用的话,点个赞吧~~也欢迎在下方评论,提出你的见解。

上一篇 下一篇

猜你喜欢

热点阅读