目录
10.2 Android 多线程编程
如果你熟悉 Java 的话,对多线程编程一定不会陌生吧。当我们需要执行一些耗时操作,比如发起一条网络请求时,考虑到网速等其他原因,服务器未必能够立刻响应我们的请求,如果不将 这类操作放在子线程里运行,就会导致主线程被阻塞,从而影响用户对软件的正常使用。下面就让我们从线程的基本用法开始学起吧。
10.2.1 线程的基本用法
Android 多线程编程其实并不比 Java 多线程编程特殊,基本是使用相同的语法。比如,定义一 个线程只需要新建一个类继承自 Thread,然后重写父类的 run() 方法,并在里面编写耗时逻辑 即可,如下所示:
class MyThread : Thread() {
override fun run() {
// 编写具体的逻辑
}
}
那么该如何启动这个线程呢?其实很简单,只需要创建 MyThread 的实例,然后调用它的 start() 方法即可,这样 run() 方法中的代码就会在子线程当中运行了,如下所示:
MyThread().start()
当然,使用继承的方式耦合性有点高,我们会更多地选择使用实现 Runnable 接口的方式来定义 一个线程,如下所示:
class MyThread : Runnable {
override fun run() {
// 编写具体的逻辑
}
}
如果使用了这种写法,启动线程的方法也需要进行相应的改变,如下所示:
val myThread = MyThread()
Thread(myThread).start()
可以看到,Thread 的构造函数接收一个 Runnable 参数,而我们创建的 MyThread 实例正是一 个实现了 Runnable 接口的对象,所以可以直接将它传入 Thread 的构造函数里。接着调用 Thread的 start() 方法,run() 方法中的代码就会在子线程当中运行了。
当然,如果你不想专门再定义一个类去实现 Runnable 接口,也可以使用 Lambda 的方式,这种写法更为常见,如下所示:
Thread {
// 编写具体的逻辑
}.start()
以上几种线程的使用方式你应该不会感到陌生,因为在Java 中创建和启动线程也是使用同样的 方式。而 Kotlin 还给我们提供了一种更加简单的开启线程的方式,写法如下:
thread {
// 编写具体的逻辑
}
这里的 thread 是一个 Kotlin 内置的顶层函数,我们只需要在 Lambda 表达式中编写具体的逻辑就可以了,连 start() 方法都不用调用,thread 函数在内部帮我们全部都处理好了。
了解了线程的基本用法后,下面我们来看一下Android 多线程编程与 Java 多线程编程不同的地 方。
10.2.2 在子线程中更新UI
和许多其他的 GUI 库一样,Android 的 UI 也是线程不安全的。也就是说,如果想要更新应用程序里的 UI 元素,必须在主线程中进行,否则就会出现异常。
眼见为实,让我们通过一个具体的例子来验证一下吧。新建一个 AndroidThreadTest 项目,然后修改 activity_main.xml 中的代码,如下所示:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"