上一篇:
上一篇我们从源码中看到IntentService内部的线程机制,是采用HandlerThread来实现的,这里我们就来深度解析下HandlerThread。推荐先看一下Handler机制详解(实例 + 源码)
先看个源码吧!毕竟很简单!
Handler是用于线程通讯的。HadndlerThread 是带Handler的子线程。
- 我们一般是子线程往主线程发消息,例如更新UI进度之类的。可以直接在主线程new Handler()。
- 一些特殊情况下,主线程需要往子线程发消息,需要在子线程创建Looper、Handler对象,用于接收处理消息
HandlerThread源码
-
name指定线程名字
-
priority代表优先级。优先级范围为-20到19,默认为0,优先级越高,获得的CPU资源更多,反之则越少。-20代表优先级最高,反之19最低。注意使用的是 android.os.Process 而不是 java.lang.Thread 的优先级!
-
onLooperPrepared() 可以做一些初始化工作,在Looper.loop()之前调用
HandlerThread用于和子线程进行通讯:
-
普通线程,调用start(),虚拟机会切换线程执行run()方法
-
HandlerThread在子线程中创建Looper、MessageQueue、Handler对象,通过这个handler给子线程发送消息,子线程接收到能做出相应处理
-
- 在run()方法中,也就是子线程中
Looper.prepare(),创建一个子线程的looper对象、MessageQueue对象
Looper.loop(),遍历,取出消息进行执行
- 在run()方法中,也就是子线程中
-
- 提供getLooper()方法,如果线程存活,且mLooper不为空,则返回Looper对象(可能mLooper创建需要一定时间)
-
- 提供getThreadHandler()方法,返回一个指定looper对象的handler对象,也就是处于子线程中handler对象
-
- 提供quit()、quitSafely()方法,用于退出looper
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;
}
//指定线程的优先级,注意使用的是 android.os.Process 而不是 java.lang.Thread 的优先级!
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
//子类可以重写,在这里做一些执行前的初始化工作
protected void onLooperPrepared() {
}
@Override
public void run() { //当调用thread.start()后,会执行run方法
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll(); //Looper 已经创建,唤醒等待获取 Looper 的线程
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
//获取当前线程的 Looper,如果线程尚未启动或者已经dead,就返回 null
//如果线程已经启动但Looper 还没初始化完成,这个方法会阻塞直到looper已经准备好,并返回Looper对象
public Looper getLooper() {
if (!isAlive()) {
return null;
}
synchronized (this) {
while (isAlive() && mLooper == null) { //循环等待,直到mLooper != null
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
public int getThreadId() {
return mTid;
}
}
实例讲解
这里只是为了实现方便,可能会存在内存泄露问题。
大致场景是:
1、主线程叫子线程去做事 (定义一个子线程的Handler,就是threadHandler啦,threadHandler.sendMessage)
2、子线程执行完毕,通知主线程 (threadhandler.handleMessage处理耗时任务)
3、主线程收到消息,更新UI或者其它的
public class HandlerThreadActivity extends AppCompatActivity {
private Button downloadBtn;
private TextView displayTv;
private int count = 1;
//UI线程的Handler,可以更新UI
private Handler mUIHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Log.e("zhen", "主线程Handle收到任务 " + msg.what +
"的反馈,很满意! thread: " + Thread.currentThread().getId());
displayTv.setText("主线程Handle收到消息 "+ msg.what);
return true;
}
}) ;
private HandlerThread mHandlerThread; //创建一个带Looper的线程
private Handler mHandler; //以子线程的Looper为入参创建一个子线程的Handler
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_thread);
initView();
intHandler();
}
private void intHandler() {
mHandlerThread = new HandlerThread("zhen");
mHandlerThread.start(); //必须要HandlerThread.start之后才能创建Handler,不然Looper.mQueue为空
mHandler = new Handler(mHandlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.e("zhen","子线程里handle收到任务" + msg.what +
",并开始处理 threadId: " + Thread.currentThread().getId());
try {
int progress = 0;
do{
Thread.sleep(2000); //mHandler的handleMessage是在子线程中执行的
progress += 20;
Log.d("zhen","子线程工作进度" + progress + "% ....");
} while (progress < 100);
Log.e("zhen","子线程任务" + msg.what +
"执行完,通知UI线程 threadId: " + Thread.currentThread().getId());
mUIHandler.sendEmptyMessage(msg.what);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}
private void initView() {
downloadBtn = findViewById(R.id.downloadBtn);
displayTv = findViewById(R.id.displayTv);
downloadBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.sendEmptyMessage(count);
Log.e("zhen","主线程给子线程handle发出任务" + count +
",开始工作啦! threadId: " + Thread.currentThread().getId());
count++;
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
mHandlerThread.quit();
}
}
1、点击downloadBtn一次:
2、点击downloadBtn两次:
是不是很类似IntentService的效果,在子线程中顺序执行(因为是一次执行完一个msg,再去执行下一个msg啦)
另外是不是感觉这日志有3D效果,看的眼睛疼。