HandlerThread

HandlerThread

十一月 08, 2017

HandlerThread

1.Handler是什么?

1.1 handlerThread产生背景

开启Thread子线程进行耗时操作

多次创建和销毁线程是很消耗系统资源的

(通过阻塞等待)

handler + thread + looper

一个内部有looper的thread

(普通handler如果创建在子线程, 由于handler消息处理需要一个messagequeen的looper, 但默认创建子线程时候没有looper就会发生异常报错;
如果想在子线程中创建一个handler就必须手动初始化looper,调用looper.loop()方法开启循环)

1.2 handlerThread 的特点

  • HandlerThread 本质上是一个线程类, 它继承了Thread;
  • HandlerThread 有自己的内部Looper对象, 可以进行looper循环;
  • 通过获取HandlerThread的looper对象传递给Handler对象,可以在handleMessage()方法中执行异步任务;
  • 有点是不会有阻塞, 减少了对性能的消耗;
  • 缺点是不能同时进行多任务的处理, 需要等待进行处理, 处理效率较低;
  • 与线程池注重并发不同, HandlerThread是一个串行队列, HandlerThread背后只有一个线程;

2. HandlerThread源码解析

2.1 构造方法

构造方法里可设置名称和优先级;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}

/**
* Constructs a HandlerThread.
* @param name
* @param priority The priority to run the thread at. The value supplied must be from
* {@link android.os.Process} and not from java.lang.Thread.
*/
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;//设置优先级
}

2.2 onLooperPrepared()空方法

可以在需要的时候去复写它, 它执行在loop之前;

1
2
3
4
5
6
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}

2. 3 run()方法;

synchronized: 当有两个并发线程访问同一个对象, 一个时间内只能有一个线程得到执行;
而另一个线程也要执行, 就必须等待另一个线程也执行完;(这里通知的是getLooper()中的wait())

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();// 初始化looper
synchronized (this) {// 保证线程间数据安全
mLooper = Looper.myLooper();
notifyAll();// 通知当前等待的线程
}
Process.setThreadPriority(mPriority);// 给线程设定优先级(可以解决内存泄露*1)
onLooperPrepared();
Looper.loop();// 开启循环
mTid = -1;
}

2.4 getLooper():

在获取mylooper时候存在一个同步问题, 只有当上面线程创建成功, looper对象也创建成功时, 才会通知下面的;wait();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason isAlive() returns false, this method will return null. If this thread
* has been started, this method will block until the looper has been initialized.
* @return The looper.
*/
public Looper getLooper() {
if (!isAlive()) {
return null;
}

// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) { // 如果looper没创建成功则一直阻塞
try {
wait();// 被run()方法中的notifyAll()通知
} catch (InterruptedException e) {
}
}
}
return mLooper;
}

2.5 quit():

退出消息循环, 退出线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* Quits the handler thread's looper.
* <p>
* Causes the handler thread's looper to terminate without processing any
* more messages in the message queue.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p class="note">
* Using this method may be unsafe because some messages may not be delivered
* before the looper terminates. Consider using {@link #quitSafely} instead to ensure
* that all pending work is completed in an orderly manner.
* </p>
*
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
*
* @see #quitSafely
*/
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}

2.6 quitSafely():

退出消息循环, 退出线程(效率上不是很高, 但更安全)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* Quits the handler thread's looper safely.
* <p>
* Causes the handler thread's looper to terminate as soon as all remaining messages
* in the message queue that are already due to be delivered have been handled.
* Pending delayed messages with due times in the future will not be delivered.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p>
* If the thread has not been started or has finished (that is if
* {@link #getLooper} returns null), then false is returned.
* Otherwise the looper is asked to quit and true is returned.
* </p>
*
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
*/
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}