HandlerThread 是一种可以使用 Handler 的线程。在日常开发中,我们经常需要创建一个 Thread 来执行任务。当有多个任务时,可能会出现线程同步问题。然而,如果我们并不需要很强的并发性,只需确保按照顺序执行各个任务,是否有更好的方法实现呢?
首先,我们可以想到通过 Executors.newSingleThreadExecutor() 方法创建一个 SingleThreadExecutor,将所有任务统一到一个线程中,然后按顺序执行。实际上,除了这个方法之外,HandlerThread 也可以实现。
下面是一个简单的使用示例:
1. 首先创建一个 HandlerThreadActivity:
```java
private static final int THREAD_COUNT = 5;
private static final String TAG = "HandlerThreadActivity";
private static final int TIMES = 10;
private Handler mHandler;
private HandlerThread mThreadPool[];
private MyRunnable mRunnable;
public void init() {
mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d(TAG, "handleMessage:" + msg.what);
}
};
mRunnable = new MyRunnable();
mThreadPool = new HandlerThread[THREAD_COUNT];
for (int i = 0; i < THREAD_COUNT; i++) {
mThreadPool[i] = new HandlerThread(TAG + i);
mThreadPool[i].start();
}
}
```
2. 在 `MyRunnable` 类中实现 `Runnable` 接口:
```java
class MyRunnable implements Runnable {
private int mCount;
public MyRunnable() {
mCount = TIMES;
}
@Override
public void run() {
while (mCount > 0) {
mHandler.sendEmptyMessage(1); //发送消息给主线程处理,此处为空消息,表示当前没有任务需要处理,只是为了通知主线程继续执行后续操作。实际应用中,可以根据需求发送其他类型的消息。
mCount--; //每次循环减少一次任务数量,直到任务全部完成。
}
}
}
```
3. 在 `Activity` 或者 `Fragment` 中调用 `init()` 方法初始化线程池:
```java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init(); //初始化线程池。注意:在子线程中不能直接更新 UI,需要通过回调或者消息机制将结果传递给主线程进行更新。因此,在子线程中执行耗时操作时,需要将结果保存到一个变量中,然后在主线程中进行更新。
以下是重构后的内容,我将原始代码分解成了更小的函数和类来提高代码的可维护性和可读性。
```java
public class HandlerThreadActivity extends BaseActivity {
private static final String TAG = "HandlerThreadActivity";
private Button mStartBtn;
private Handler mHandler;
private HandlerThread mHandlerThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_thread);
initViews();
startHandlerThread();
}
private void initViews() {
mStartBtn = findViewById(R.id.start_btn);
}
private void startHandlerThread() {
mHandlerThread = new HandlerThread("THREAD_NAME");
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
}
mStartBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.post(new Runnable() {
@Override
public void run() {
Log.d(TAG, Thread.currentThread().getId() + " " + String.valueOf((Looper.myLooper() == Looper.getMainLooper())) + " 任务:" + this.hashCode());
SystemClock.sleep(3000);
}
});
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
mHandlerThread.quit();
}
```
在这个重构后的版本中,我创建了两个新的私有方法:`initViews()`和`startHandlerThread()`。`initViews()`方法负责初始化视图,包括`mStartBtn`按钮。而`startHandlerThread()`方法负责启动并设置处理线程。这两个方法都直接在`onCreate()`方法中调用,使得代码更加清晰,也避免了全局变量的使用。
在Python中,线程的执行通常具有并发性,但并不意味着它们会按照创建的顺序运行。如果您想控制线程的执行顺序,可以使用join()方法。join()方法使当前线程“阻塞”,等待指定线程执行完毕后继续执行。
您可以使用以下代码来实现子线程中的任务按开始的顺序执行:
```python
import threading
def task1():
print("task1 start")
# do something
print("task1 end")
def task2():
print("task2 start")
# do something
print("task2 end")
t1 = threading.Thread(target=task1)
t2 = threading.Thread(target=task2)
t1.start()
t1.join()
t2.start()
t2.join()
```
```java
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
private @Nullable Handler mHandler;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
protected void onLooperPrepared() {
}
@Override
public void run() {
// 获取线程 id
mTid = Process.myTid();
//构建一个 Looper
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
//设置线程优先级
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
// Looper 循环
mTid = -1;
}
/**
* @return a shared {@link Handler} associated with this thread
*/
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
/**
* @return the thread id of this thread
*/
public int getThreadId() {
return mTid;
}
}
```
HandlerThread 的原理如下:
当我们调用 HandlerThread 的 start() 方法时,它会执行 run() 方法。在 run() 方法中,首先通过 Looper.prepare() 创建消息队列,然后通过 Looper.looper() 方法开启消息循环。由于 Looper.loop() 是一个死循环,因此 run() 方法也会无限循环。
当我们不再需要使用 HandlerThread 时,应调用其 quit() 方法或 quiteSafely() 方法来停止消息循环。
总结一下,HandlerThread 的工作原理是通过运行 start() 方法进入 run() 方法,在 run() 方法中创建消息队列并开始消息循环。当不再需要使用时,调用 quit() 方法或 quiteSafely() 方法停止消息循环。
在 Android 中,HandlerThread 通常用于实现 IntentService。如果你对 IntentService 感兴趣,可以点击这里了解更多信息。