为了引出HandlerThread类,我们现在先看看这样一个例子来说明Handler类和Looper类的同步关系:下面这段代码和例子出之《深入理解Android卷I》。
前面不是说到过,使用Handler来处理消息有助与分担主线程的工作,将与UI主线程无关且耗时的工作放到单独的工作线程中去,那么我们看看下面这样一个需求假设线程1是UI主线程,线程2是工作线程
class LooperThread extends Thread{
public Looper myLooper = null;
public void run(){//假设run在线程2中执行
Looper.perpare();
//myLooper必须在这个线程中赋值
myLooper = Looper.myLooper();
Looper.loope();
}
}
//下面这段代码在线程1中执行,并且会创建线程2
{
LooperThread lpThread=new LooperThread;
lpThread.start();//start后会创建线程2
Looper looper = lpThread.myLooper;//-----注意-----
//thread2Handler和线程2的Looper挂上钩
Handler thread2Handler = new Handler(looper);
//发送消息将有线程2来处理
thread2Handler.sendMessage(。。。)
}
上面这段代码的目的在于,在线程一中创建线程2,并且线程1中得到线程2中创建的Looper对象,并且用这个线程2中创建的Looper对象来实例化一个Handler类 thread2Handler,那么通过这个
thread2Handler发送出去的消息都会在线程2中得到处理。
上面这段的代码的问题在与,在线程1中给looper复制的时候线程2中的myLooper变量实例化完,这会导致在线程1中looper为null。
在看看下面这两行代码的差别:
Handler thread2Handler = new Handler(looper) //不能替换成
Handler thread2Handler = new Handler(Looper.myLooper())
因为Looper.myLooper()函数返回的是当前线程(调用线程)的Looper,即如果使用第二种写法,那么不能像我们想的那样将线程2的looper传递给线程1。
为了解决上面的问题,我们引入了HandlerThread类。
下面我看看HandlerThread的内部接口
public class HandlerThread extends Thread {
private int mPriority;
private int mTid = -1;
private Looper mLooper;
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;
}
...
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 is 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;
}
/*下面的代码来之WifiService.java*/
HandlerThread wifiThread = new HandlerThread("WifiService");
wifiThread.start();
mWifiHandler = new WifiHandler(wifiThread.getLooper());
假设在线程1中通过wifiThread.start()来开启线程2,线程1希望把对消息的处理函数放到线程2中去,在线程2开启的时候会运行run()函数,假设此时线程1从新获得CPU继续执行,进入到函数wifiThread.getLooper()中。那么如何保证线程1和线程2在Looper变量的传递上保持同步呢?HandlerThread中使用了一个java中的wait/notify机制,不懂的同学可以google下。在run()中如果mLooper变量实例化完成过后会notify来通知要取mLooper的线程1,同样在线程1中,如果getLooper()时还没有得到mLooper,则wait()等待唤醒。
其实Android中光一个Looper Handler就够我们学的了,只是菜鸟不才,目前只能把自己大概知道的记录在这里,Ok诸位晚安,如果哪位大牛发现这篇blog有什么错误,敬请指教,免得误导了其他菜鸟....