在子线程中如何创建Handler?
Handler myHandler;
public void method(){
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
myHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
return false;
}
});
Looper.loop();
}
});
}
我们看这种方式,我们只能在线程中创建一个handler,但任何一个线程都应该能创建N多个handler,我们用这种方式无法创建,因为这一个线程是一个内部类,内部类,在外部类无法得到这个内部类的对象的,那么晚就无法拿到它的Looper,既然拿不到它的Looper,那么这种创建方式就是错误的,那么要怎么创建可以的呢?
public class MyHandlerThread extends Thread{
Looper looper;
@Override
public void run() {
super.run();
Looper.prepare();
looper = Looper.myLooper();
Looper.loop();
}
Looper getLooper() {
return looper;
}
@Override
public synchronized void start() {
super.start();
}
}
因为我们要在多个地方,线程能够创建多个handler,那么你必须要new一个handler,new handler是必须要传looper,这个loogper必须能拿到,你能拿到这个线程对应的looper,那怎么拿呢?
MyHandlerThread thread = new MyHandlerThread();
thread.start();
//这里存在着一个并发的问题
//sleep(10);//为了解决并发问题,只能在这里睡眠10毫秒,但是在Android当中使用sleep是不可取的
Handler handler1 = new Handler(thread.getLooper());//我无法保证这里的getLooper()不为null
Handler handler2 = new Handler(thread.getLooper());
这里把线程封装成一个类,之后又一个独立的对象looper,所以这时候,在这个run里面prepare一下,之后把这个looper赋值保存起来,赋值之后再调用Looper.loop(),有了这个动作,我就可以再任何地方拿到,这样子下来就可以通过new 一个线程,创建线程之后拿就把这个线程的looper创建了,创建好了之后,拿就把这个looper传进handler去。
不过这里有一个并发的问题,这里不能保证getLooper()一定就有值,因为线程的执行也不会马上给你执行到run方法里面,把值赋值好,这得看CPU的心情。解决这个问题,上面用到一种指标的方式sleep(10);这个sleep在Android当中是不能这么使用的,会造成用户画面的卡顿。
HandlerThread就为我们解决了这个并发问题。来看看他是如何解决的。
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
/**
* 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) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
在这里看到当“线程已经启动但是Looper对象还没有创建完成”时会进行等待,当创建完成时会唤醒等待,这时getLooper()就可以返回已经创建完成的Looper对象了。之所以需要这个“等待-唤醒”机制,因为获取Looper是在主线程中进行的,而创建Looper是在子线程中进行的,必须使用这个机制来完成两者的状态同步。