1. 如何在线程中实现当前线程的Handler
当我们需要在在线程里面里使用线程自己的handler的时候,需要新建一个当前线程的Looper,但是必须要初始化Looper.prepare(),同时要调用Loop.loop()。代码如下:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyThread myThread = new MyThread();
myThread.start();
try {
// 主线程休眠一秒,否则会报错
// 空指针异常Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.os.Handler.sendEmptyMessage(int)' on a null object reference
Thread.sleep(1000);
myThread.mHandler.sendEmptyMessage(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
class MyThread extends Thread {
Handler mHandler;
@Override
public void run() {
super.run();
// 创建线程的looper
Looper.prepare();
mHandler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
Log.e("MainActivity","handleMessage " + Thread.currentThread().getName());
}
};
// 开启线程looper的循环
Looper.loop();
}
}
}
打印结果如下,可以看到是线程中的handler在处理消息:
2. 向主线程的Handler传递子线程Looper
当我们尝试在主线程的Handler中传入子线程的Looper时,程序可能会报错,因为存在多线程并发的问题,当程序运行到主线程中handler的创建时,传入了子线程的Looper,如果此时子线程中的Looper还没有创建出来,传递的就是null,所以会抛出空指针异常。
public class MainActivity extends AppCompatActivity {
private Handler mainHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.e("MainActivity","main111 == " + Thread.currentThread().getName());
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyThread myThread = new MyThread();
myThread.start();
// try {
// Thread.sleep(1000);
// myThread.mHandler.sendEmptyMessage(1);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
mainHandler.sendEmptyMessage(1);
// 此处handler中传入myThread.threadLooper可能会报错,因为多线程中,当程序运行到此处时,Mythread中的looper可能还没有创建,是null
// 报错 Attempt to read from field 'android.os.MessageQueue android.os.Looper.mQueue' on a null object reference
mainHandler = new Handler(myThread.threadLooper){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.e("MainActivity","main222 == " + Thread.currentThread().getName());
}
};
mainHandler.sendEmptyMessage(2);
}
class MyThread extends Thread {
Handler mHandler;
Looper threadLooper;
@Override
public void run() {
super.run();
// 创建线程的looper
Looper.prepare();
// 取到当前线程Looper的实例
threadLooper = Looper.myLooper();
mHandler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
Log.e("MainActivity","MyThread === " + Thread.currentThread().getName());
}
};
// 开启线程looper的循环
Looper.loop();
}
}
}
错误日志如下:
而上面的问题,HandlerThread已经帮我们解决了。
HandlerThread是Thread的子类,严格意义上来说就是一个线程,只是它在自己的线程里面帮我们创建了Looper。
HandlerThread的用法:
public class HandlerThreadTest extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
HandlerThread handlerThread = new HandlerThread("my HandlerThread");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.e("HandlerThreadTest","Handler == " + Thread.currentThread().getName());
}
};
handler.sendEmptyMessage(1);
}
}
打印日志:
3. HandlerThread实现原理
我们再来看看HandlerThread的源码
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) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
getLooper方法中可以看到,当mLooper为空的时候,进入等待状态,那什么时候唤醒呢?接下来看run方法
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
在run方法中可以看到,和我们自己在线程中用Looper一样,也需要调用prepare初始化和loop开启轮询。
当然我们把重点放在这段代码上:
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
通过Looper.myLooper()
方法,把值给mLooper,再通过notifyAll()
方法唤醒在等待的当前线程的对象,这时handler就能拿到looper对象,就不会再报空指针异常的问题。
4. HandlerThread 存在的意义如下:
- 方便使用:a. 方便初始化,b. 方便获取线程Looper
- 保证了线程安全