先来看一下我自己写的一个有关ThreadLocal的例子,让我们来熟悉下ThreadLocal的用法
public class TestThreadLocal {
private static ThreadLocal<Integer> a = new ThreadLocal<Integer>() {
public Integer initialValue() {
return 0;
}
};
public static void main(String args[]) {
MyThread my = new MyThread();
my.start();
MyThread myThread2 = new MyThread();
myThread2.start();
}
public static class MyThread extends Thread {
public void run() {
for (int i = 0; i < 5; i++) {
a.set(a.get() + 1);
System.out.println(Thread.currentThread().getName() + ":"
+ a.get());
}
}
}
}
输出:
Thread-0:1
Thread-0:2
Thread-0:3
Thread-0:4
Thread-0:5
Thread-1:1
Thread-1:2
Thread-1:3
Thread-1:4
Thread-1:5
从输出很容易看出ThreadLocal<Integer> a是每个线程都有一份变量,而且ThreadLocal的set/get只和当前线程有关,请记住这个java的基本知识
接着看Looper类的定义
/**
* Class used to run a message loop for a thread. Threads by default do
* not have a message loop associated with them; to create one, call
* {@link #prepare} in the thread that is to run the loop, and then
* {@link #loop} to have it process messages until the loop is stopped.
*
* <p>Most interaction with a message loop is through the
* {@link Handler} class.
*
* <p>This is a typical example of the implementation of a Looper thread,
* using the separation of {@link #prepare} and {@link #loop} to create an
* initial Handler to communicate with the Looper.
*
* <pre>
* class LooperThread extends Thread {
* public Handler mHandler;
*
* public void run() {
* Looper.prepare();
*
* mHandler = new Handler() {
* public void handleMessage(Message msg) {
* // process incoming messages here
* }
* };
*
* Looper.loop();
* }
* }</pre>
*/
public class Looper {
从Looper的定义来看,是说明的很清楚了,我们就按官方的这个例子来说明一个个例子中的方法分析,假设调用了LooperThread().start();执行
一、Looper.prepare();
二、 Looper.loop();
先看Looper.prepare();
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
上面构造了一个Looper对象,并且放入调用线程的局部变量中,即线程的局部变量sThreadLocal存储的是Looper对象,这个Looer对象只针对当前的线程操作
看下new Looper()构造方法做了什么
private Looper() {
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
上面代码主要做了两件事
1、mQueue = new MessageQueue();构造了MessageQueue
2、mThread = Thread.currentThread();得到当前线程对象
接着看Looper.loop();
public static void loop() {
Looper me = myLooper();
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
return;
}
msg.target.dispatchMessage(msg);
msg.recycle();
}
}
}
上面的Looper me = myLooper();去除消息队列中的消息然后while循环一直检查是否有消息,如果有消息则执行下面这一句
msg.target.dispatchMessage(msg);
我们需要注意上面的msg.target的类型是
Handler target;
这里特别要注意 就是说最后还是交给了 Message 的 target ( Handler 类型)dispatchMessage(msg) 处理
我们后续需要注意下message封装消息的时候是否把Hanlder赋值给Message的target
我们接着看上面的Looper me = myLooper();
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static Looper myLooper() {
return sThreadLocal.get();
}
就是返回当前线程的ThreadLocal 对象sThreadLocal存储的Looper,而Looper的构造方法里面有其消息队列,所以会有loop方法中的
MessageQueue queue = me.mQueue;
从上面我们可以总结
1、Looper的prepare函数把Looper和prepare的线程(处理线程)绑定在一起
2、Looper构造函数封装了一个消息队列
3、处理线程调用loop函数,while一直在处理消息队列里面的消息
那么我们的消息是怎么放入消息队列的呢?我们接着看Hanlder类,先看Handler类的成员属性
final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
从上面来看Handler也有一个MessageQueue和一个Looper还有一个回调
我们接这看它的构造函数
public Handler() {
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = null;
}
public Handler(Callback callback) {
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
}
public Handler(Looper looper) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = null;
}
public Handler(Looper looper, Callback callback) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
}
从上面的重载的构造函数来看,就是Looper有可能是传入的有可能是当前线程的,还有个区别就是callback是否为空
Hanlder主要做了些什么事呢?我们来看下他的一些方法
1、obtainMessage 创建消息
2、sendMessage 加入消息队列
3、hasMessages 判断队列中是否还有消息
4、removeMessages 移除消息
我们看怎么把消息加入到消息队列的,我们接着看
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
{
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this;
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
上面的代码其中分析如下:
1、MessageQueue queue = mQueue 这里的mQueue是Handler的变量成员,是通过Handler构造器里面通过mLooper.mQueue而来的,而这个mLooper有可能是构造器传入的参数,也有可能是当前的执行线程的Looper
2、 msg.target = this; 解决了我之前的疑问======》我们后续需要注意下message封装消息的时候是否把Hanlder赋值给Message的target
3、queue.enqueueMessage(msg, uptimeMillis);把封装的消息放入消息队列,有关enqueueMessage这个方法这里就不展开了:通过这个方法的注释已经说明的很清楚:Enqueue a message into the message queue after all pending messages
上面都是消息封装,我们来看下其消息是怎么处理的
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
上面的代码的意思是如果Message的callback没有,则执行Hanlder的callback,如果Hanlder也没有callback,则执行handleMessage,有关这个callback就是一个回调,正常在封装消息或Handler的时候是一个Runnable如下面
public final boolean postDelayed(Runnable r, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
private final Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
下面是展示的一个有关回调的一个例子
private final Handler handler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case MSG_TIMER:
mWorker = new HandlerThread("MyWorker");
mWorker.start();
mWorkerHandler = new Handler(mWorker.getLooper());
mWorkerHandler.postDelayed(new MessageReceiveTask(),
SECONDRESOLVERMESSAGE);
break;
}
}
};
public void onCreate() {
super.onCreate();
Log.i(Constant.TAG_INFO,
"StartService*****************************************");
Message msgget = Message.obtain();
msgget.what = MSG_TIMER;
handler.sendMessageDelayed(msgget, SECONDRESOLVERMESSAGELONG);
}
class MessageReceiveTask implements Runnable {
public void run() {
try {
loadInitInboxData();
} catch (Exception e) {
Log.i(Constant.TAG_EXCEPTION, "MessageReceiveTask : " + e);
}
mWorkerHandler.postDelayed(this, SECONDRESOLVERMESSAGE);
}
}
我们再回到刚开始Looper例子
class LooperThread extends Thread {
public Looper myLooper = null;
public Handler mHandler;
public void run() {
Looper.prepare();
myLooper = Looper.myLooper();
Looper.loop();
}
}
LooperThread thread1 = new LooperThread()
thread1.start
Looper lp = thread1.myLooper;
Hanlder hanler = new Handler(lp);
hanler.sendMessage();
从上面来看,主要的处理是放在非主线程中执行的
所以
Handler handler = new Handler(looper)
不能写成
Handler handler = new Handler(Looper.myLooper())
这里的Looper.myLooper()是主线程的
那么它又是怎么解决上面的问题呢,源码中的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;
}
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
从上面来看是在非主线程中创建了looper,然后通过notifyAll来唤醒直接返回非主线程的mLooper,下面是更好的说明的之前的例子
mWorker = new HandlerThread("MyWorker");
mWorker.start();
mWorkerHandler = new Handler(mWorker.getLooper());
mWorkerHandler.postDelayed(new MessageReceiveTask(),
SECONDRESOLVERMESSAGE);
到此基本ok了