ThreadLocal 的作用就是一个 Map<Thread,Ojbect>, 也就是说 ThreadLocal 中存放的是和一个线程相关的某一个对象,其实 ThreadLocal是为线程同步准备的,线程同步还有另
外一种方式就是使用synchronized关键字,但这种同步方法效率效低,而使用ThreadLocal则效率高点. 总之,了解到 ThreadLocal相当于一个Map<Thread,Object>,用于线程同步即可.在 android.os.Looper中有下面一行:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
因为它是static的,这里我们把 sThreadLocal 看成是一个
全局变量.
一个Looper对象有哪些成员呢?
public class Looper {
private static final String TAG = "Looper";
//一个消息队列
final MessageQueue mQueue;
}
Android文档里说, “一个Thread可以关联一个 MessageQueue”,关联示意图如下图所示:
一个线程通过 ThreadLocal 和一个 Looper 对应,即 Map<ThreadLocal,Looper>, 而一个Looper拥有一个 MessageQueue,所以一个 Thread就和一个 MessageQueue关联起来了.
一个 Thread 本来是没有和 MessageQueue关联的,关联的过程通过下面一个全局函数(因为是静态的,暂且当作是全局的)来实现:
//Looper.java 中的一个方法
public static void prepare() {
//调用此方法的线程是否在 全局变量 sThreadLocal(即Map<Thread,Looper>)中存有一组以此线程为键的键值对
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//如果在Map<Thread,Looper>中没有存放当前线程对应的键值对当存入
// 一个 set 操作,其实就是在 Map 中插入了一组 <Thread,Looper>值,即 <调用此方法的线程,new Looper()>
// new Looper() 时,Looper的构造函数就会实例化一个 MessageQueue
sThreadLocal.set(new Looper());
}
通过以上阐述,我们了解 存在一个全局的 ThreadLocal,它是一个Map<Thread,Looper>型的变量,一个线程在调用 prepare( )全局函数后都会在ThreadLocal中存在一组以当前线程为键的键值对,这个键值对所关键的值就是一个Looper对象,一个Looper对象有一个MessageQueue,这样一个线程就和一个MessageQueue关联起来.
一个 Handler 是什么东西?它的作用是什么?
一个Handler共有两个作用: 1 向某一线程的 MessageQueue 插入 Message 2 处理某一线程的 MessageQueue 取出的 Message
Handler的作用主要围绕 MessageQueue, 它即向 MessageQueue中插入信息,同时也处理 MessageQueue 弹出的 Message.
插入信息的方法如下:
处理信息的方法如下:
那么现在考虑下面一段非常常见的代码(为了完整性把无用的代码也贴出来了):
import android.app.Activity;
import android.graphics.drawable.ClipDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.ImageView;
public class MainActivity extends Activity {
public static final int WHAT = 1;
private ClipDrawable mDrawable;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView view = (ImageView)findViewById(R.id.view);
mDrawable = (ClipDrawable)view.getDrawable();
new ProgressThread(mHandler).start();
}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if(msg.what == MainActivity.WHAT) {
mDrawable.setLevel(mDrawable.getLevel() + 500);
}
}
};
private class ProgressThread extends Thread {
//这里暂不考虑线程同步
private Handler mHandler;
public ProgressThread(Handler handler) {
mHandler = handler;
}
@Override
public void run() {
Message msg;
for(int i = 0; i < 20; i++) {
msg = mHandler.obtainMessage(MainActivity.WHAT);
mHandler.sendMessage(msg);
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
这段代码的常见之处就是:
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if(msg.what == MainActivity.WHAT) {
mDrawable.setLevel(mDrawable.getLevel() + 500);
}
}
};
我们把 Handler 当做一个 Activity 的成员变量,并对它进行实例化,那么实例化时发生了什么呢? 看一下 android.os.Handler的默认构造函数源码:
public Handler() {
//获得当前线程在 ThreadLocal 中所对应的 Looper
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;
}
Handler的默认构造函数会得到当前线程的Looper,并通过这个Looper获得 MessageQueue, 获得MessageQueue以后就可以往里面 send 信息了.
也就是说,当你实例化一个 Handler时,这个 Handler就和当前这个线程的 MessageQueue 相关联,它能作用于这个 MessageQueue的两头(插入信息/处理弹出的信息).
当你把这个Handler的引用传给其它Thread时,那个Thread就可以通过 Handler 与Handler所关联的线程进行交互. 如下图:
Thread2 通过 mHandler.sendMessage( ) 向线程1 发出异步的 Message, Thread1 通过 handleMessage( ) 来处理来自于 Thread2 的 Message.
可以更直接的认为你建立的 Handler实例就代表一个线程,它是两个线程间通信的桥梁.
还有一些问题需要思考?
问题一:
一个Thread 必须要经过 Looper.prepare( ) 才能拥有自己的 MessageQueue, 而我们在Activity的类是定义一个Handler内部类来使用时,系统不会报错,也就是说Activity这个线程已经在某些地方调用过 Looper.prepare( ) 来生成自己的消息队列,这个太复杂了,没有搞懂,但能在Activity源码中发现下面几行代码:
public void recreate() {
if (mParent != null) {
throw new IllegalStateException("Can only be called on top-level activity");
}
if (Looper.myLooper() != mMainThread.getLooper()) {
throw new IllegalStateException("Must be called from main thread");
}
mMainThread.requestRelaunchActivity(mToken, null, null, 0, false, null, false);
}
具体的内部机制暂时搞不清了!
问题二:
一个线程的 MessageQueue 要经过 Looper.loop( ) 才能把消息弹出,并调用 Message.target.dispatch(Message ) 方法, 在这里 loop( ) 方法内部有一个 while(true)的无限循环,如果这个方法是在当前线程执行的话,当前线程就会被卡死,如果不是在当前线程执行的话,那么由哪一个线程在执行呢? framework里是如何实现的呢?