接上篇 我终于读懂了Handler(一)
经过上一篇的阅读,相信你对handler已经有了一定的理解。本篇就开始进行实践
1. 多个handler在多线程中的应用
public class HandlerTestActivity extends AppCompatActivity {
private static final String TAG = "HandlerTestActivity";
private Handler mHandler;
private Handler mHandler1;
private MyThread mThread1;
private Handler mHandler2;
private MyThread mThread2;
class MyThread extends Thread {
private Looper mLooper;
@Override
public void run() {
super.run();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Looper.loop();
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mThread1 = new MyThread();
mThread1.start();
mThread2 = new MyThread();
mThread2.start();
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d(TAG,"get Message =="+msg.what);
}
};
new Thread(() -> mHandler.sendEmptyMessage(10)).start();
mHandler.sendEmptyMessage(0);
mHandler1 = new Handler(mThread1.getLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d(TAG,"get Message =="+msg.what);
}
};
mHandler1.sendEmptyMessage(1);
mHandler2 = new Handler(mThread2.getLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d(TAG,"get Message =="+msg.what);
}
};
mHandler2.sendEmptyMessage(2);
}
}
输出结果:
这里我们实验了多个线程之间发送消息的情况。
- Handler默认实例化和Handler指定Looper对象实例化的比较
- handler在主线程发送消息和在子线程发送消息的比较
- 上一篇中我们也举过一下在子线程实例化Handler对象的例子。
这样我们对Handler的理解应该更加清晰了吧!这里我们探究一下多线程中为何要像上面例子一样实现。
1.1 指定Looper对象
首先我们要明白一点,在上面的例子中可不可以不指定Looper对象(也就是说61行mThread1.getLooper()可不可以没有)。 答案是:可以。 即使我们加一行代码new Thread(() -> mHandler1.sendEmptyMessage(12)).start();handler1在子线程中发送消息它还是可以收到,既然这样我们是不是不需要指定Looper对象?
如果我们没有指定Looper对象,那么我们就是用的主线程的Looper;现在我们指定了mThread1.getLooper(),mHandler1中用的就是Thread1中的Looper对象。在这里当然看不出会出什么问题,但是如果我们的Handler1是在子线程进行实例化的,那么我们就一定要指定Looper对象了,不然发送消息的时候程序怎么知道你要存到哪个线程的消息队列呢。
1.2 getLooper()
mThread1.getLooper()时MyThread的run方法执行了,Looper.prepare可能还没执行,所以在getLooper方法里面用wait等待,当Looper.prepare()执行了再notifyAll,这里加了把锁保证了线程安全。
一般情况下我们使用默认的Handler实例化完全可以满足我们的日常开发需求。而上面MyThread类的创建完全是为了让我们在子线程中实例化handler进行的封装,而且是比较简陋的封装,Android系统为我们提供了更好的——HandlerThread。
2. HandlerThread的引入
HandlerThread比上面的MyThread考虑的更全面,而且它是核心类库自带的,我们直接用就行。
public class HandlerThreadActivity extends AppCompatActivity {
private static final String TAG = "HandlerThreadActivity";
private HandlerThread mHandlerThread;
private HandlerThread mHandlerThread1;
private HandlerThread mHandlerThread2;
private Handler mHandler;
private Handler mHandler1;
private Handler mHandler2;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandlerThread = new HandlerThread("handler-thread");
mHandlerThread.start();
mHandlerThread1 = new HandlerThread("handler-thread1");
mHandlerThread1.start();
mHandlerThread2 = new HandlerThread("handler-thread2");
mHandlerThread2.start();
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d(TAG,"get Message ==="+msg.what);
}
};
new Thread(()-> {
mHandler1 = new Handler(mHandlerThread1.getLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d(TAG,"get Message ==="+msg.what);
}
};
mHandler.sendEmptyMessage(0);
mHandler1.sendEmptyMessage(1);
}).start();
new Thread(()-> {
mHandler2 = new Handler(mHandlerThread2.getLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d(TAG,"get Message ==="+msg.what);
}
};
mHandler2.sendEmptyMessage(10);
}).start();
}
@Override
protected void onResume() {
super.onResume();
mHandler2.sendEmptyMessage(2);
}
}
输出结果:
这里简单的使用了一下,着重了多线程中实例化Handler的情况。
第38行我们就使用了上篇中的例子,同时也是子线程做耗时操作,然后向主线程发送消息的例子,这里我们发了一个空消息,所以不需要构造消息对象。
第30行我们创建了一个线程(这里命名为子线程1),第43行我们又创建了一个线程(这里命名为子线程2),本来想让举个这两个子线程间通信的例子。但是我如果从子线程2向子线程1发送消息的话mHandler2.sendEmptyMessage(1000),有可能子线程1还未创建,所以就没举子线程间通信的例子。但是我们应该明白handler在线程间通信的优越性和它的可行性。