文章目录
- 目的
- Java中的多线程
- Thread
- Runnable
- Timer
- Android中的多线程
- Handler
- AsyncTask
- 总结
目的
Android中UI线程对于开发者和用户来说都是最主要接触到的线程。一般来说为了UI流畅、不卡顿,耗时操作是不推荐放在UI线程中的。但是耗时操作的需求又是存在的,这时候就需要用到多线程编程了,新建一条子线程去处理耗时操作。这篇文章将对相关内容进行简单介绍。
Java中的多线程
Android应用大部分都是用Java开发的,所以Java中的一些多线程编程方式在Android里也是可以使用的。
Thread
这是最基本的多线程操作:
// 定义继承自Thread的类
class MyThread extends Thread {
// 重写run方法
public void run() {
// TODO
}
}
MyThread t = new MyThread();
t.start(); // 创建新线程并启动,线程启动后会运行其中run方法
// new MyThread().start(); // 直接启动方式
Runnable
前面用的是继承的方式,只能继承一个类,所以更加常见的是使用下面这种方式:
// 定义类来实现Runnable接口
class MyRunnable implements Runnable {
// 实现接口中的run方法
public void run() {
// TODO
}
}
Thread t = new Thread(new MyRunnable());
t.start(); // 创建新线程,线程启动后会运行其中run方法
// new MyThread().start(); // 直接启动方式
很多时候也可以直接使用匿名内部类方式:
// 匿名内部类方式
Thread t = new Thread(new Runnable(){
public void run() {
// TODO
}
});
t.start();
Timer
上面演示中在子线程中每隔1000ms执行一次操作,如果只是需要这种定时任务的话使用定时器更加方便些:
// import java.util.Timer;
// import java.util.TimerTask;
Timer timer = new Timer(); // Timer用来调度运行TimerTask对象
// 一个Timer可以调度多个TimerTask
TimerTask task = new TimerTask() {
public void run() {
// TODO
}
};
// timer.schedule(task, 2000); // 延迟2000ms后运行一次task
timer.schedule(task, 2000, 1000); // 延迟2000ms后运行一次task,然后每隔1000ms重复运行task
Android中的多线程
Android中子线程是不能更新UI的,但很多时候又需要子线程处理一些耗时操作,然后根据操作结果来更新UI。针对这个业务需求Android中又提供了一些多线程机制。
Handler
Handler本身并不是多线程,它只是提供一种机制,使一个线程可以发送消息给另一个线程,通常默认情况下就是子线程发送消息给UI线程,这样UI线程就可以根据接收到的消息来做对应的处理,比如更新UI元素等。
Handler通常和前面Java的多线程方式结合使用。下面是个简单的演示:
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.TextView;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class MainActivity extends AppCompatActivity {
// 声明Handler对象并重写handleMessage方法
@SuppressLint("HandlerLeak")
private final Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) { // 收到消息时会触发handleMessage方法
// 这个Handler对象在哪个线程,handleMessage方法就在哪个线程执行
TextView text = findViewById(R.id.text);
text.setText(msg.obj.toString());
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Timer().schedule(new TimerTask() {
public void run() {
Message message = new Message(); // 新建消息
message.obj = new Date(System.currentTimeMillis()); // 填充消息内容
handler.sendMessage(message); // 发送消息
}
}, 2000, 2000); // 每两秒触发一次定时器子线程
}
}
上面演示中子线程可以创建 Message
对象,这个对象中可以保存 obj
等很多东西。通过 Handler
对象的一些方法,比如上面 sendMessage()
方法可以将 Message
发送给 Handler
所在线程。在 Handler
所在线程中会有 MessageQueue
用来接收这些 Message
,还有 Looper
进行消息处理,最终调用 Handler
对象的 handleMessage()
方法。在UI线程中 MessageQueue
和 Looper
默认都会自动创建的。
现在的Android版本中上面这样的使用方式会被认为可能引起Activity泄漏,可以改用下面方式:
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.TextView;
import java.lang.ref.WeakReference;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class MainActivity extends AppCompatActivity {
private static class MyHandler extends Handler {
//弱引用持有MainActivity , GC 回收时会被回收掉
private final WeakReference<MainActivity> weakReference;
public MyHandler(MainActivity activity) {
this.weakReference = new WeakReference(activity);
}
@Override
public void handleMessage(Message msg) {
MainActivity activity = weakReference.get();
if (activity != null) {
TextView text = activity.findViewById(R.id.text);
text.setText(msg.obj.toString());
}
}
}
private final MyHandler myHandler = new MyHandler(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Timer().schedule(new TimerTask() {
public void run() {
Message message = new Message();
message.obj = new Date(System.currentTimeMillis());
myHandler.sendMessage(message);
}
}, 2000, 2000);
}
}
AsyncTask
AsyncTask是Android另一个用来异步更新UI的方式,现在(API level 30,Android 11)已被弃用,这里就不再进行介绍了。
总结
多线程的基础操作是比较简单的,相对复杂的线程间同步互斥等的问题先不在这里展开,使用时注意下不同线程对同一个资源操作的问题即可。