Handler
允许我们在一个线程的消息队列(MessageQueue
)里面发送、处理Message
和Runnable
,每一个Handler
只能在一个线程和一个消息队列(MessageQueue
),当我们创建Handler
时,这个Handler
与当前线程和当前线程里面的消息队列(MessageQueue
)关联,当线程执行操作结束后,Handler
可以将消息分发出去。
Handler中我们使用频率较高的是post(Runnable r)
和sendMessage(Message msg)
,通过源码我们可以看到都调用了将当前Message
加入消息队列,然后当前线程的Looper
通过获取当前的MessageQueue
获取消息再发送个Handler
,由Handler
分发给拥有这个Handler
的线程(必须是拥有Handler
的线程)。
/**
* Causes the Runnable r to be added to the message queue.
* The runnable will be run on the thread to which this handler is
* attached.
*
* @param r The Runnable that will be executed.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
/**
* Pushes a message onto the end of the message queue after all pending messages
* before the current time. It will be received in {@link #handleMessage},
* in the thread attached to this handler.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
/**
* Enqueue a message into the message queue after all pending messages
* before the absolute time (in milliseconds) uptimeMillis.
* The time-base is {@link android.os.SystemClock#uptimeMillis}.
* Time spent in deep sleep will add an additional delay to execution.
* You will receive it in {@link #handleMessage}, in the thread attached
* to this handler.
*
*/
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
public class MainActivity extends Activity {
private ImageView image;
private Handler mHandler = new Handler(){
/**
* 获取子线程中消息队列发送的Message
* @param msg
*/
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bitmap bm = (Bitmap) msg.obj;
image.setImageBitmap(bm);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
image = (ImageView) findViewById(R.id.image);
new MyThread(mHandler).start();
}
private class MyThread extends Thread{
private Handler mHandler;
public MyThread(Handler handler){
this.mHandler = handler;
}
@Override
public void run() {
//1.耗时操作,比如请求网络
try {
HttpURLConnection connection = (HttpURLConnection) new URL("http://h.hiphotos.baidu.com/image/pic/item/e7cd7b899e510fb300679675da33c895d0430cd1.jpg").openConnection();
connection.setConnectTimeout(5000);
connection.setReadTimeout(20000);
InputStream is = connection.getInputStream();
Bitmap bm = BitmapFactory.decodeStream(is);
//2.结果包装到Message
Message msg = new Message();
msg.obj = bm;
//3.handler将消息发送给主线程(一般式UI线程)
mHandler.sendMessage(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
HandlerThread是一个拥有looper的线程,这个looper可以用来创建handler,启动这个线程需要调用start().
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = android.os.Process.THREAD_PRIORITY_DEFAULT;
}
/**
* 构造方法
* @param name thread的name
* @param priority 优先级
*/
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
/**
* 回调方法,可以被复写
*/
protected void onLooperPrepared() {
}
@Override
public void run() {
//获取线程id
mTid = Process.myTid();
//将当前线程初始化为Looper线程
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
//开始循环处理消息队列
Looper.loop();
mTid = -1;
}
/**
* 这个方法返回和此线程相关的Looper,如果这个线程没有启动或者isAlive()返回false,Looper将返回null,
* 如果这个线程已经启动,这个方法将会阻塞,一直到looper实例化后。
* @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;
}
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
/**
* 停止
* @return
*/
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
/**
* 获取线程id
*/
public int getThreadId() {
return mTid;
}
}
Looper的字面意思就是“循环者”,一个普通线程通过它可以变成一个循环线程,上文中的HandlerThread就是典型的例子,在平时开发中,我们经常需要一个循环线程,一旦有新任务则执行,执行完毕后必须等待下一个任务,这就是Looper线程。使用Looper创建线程也很简单。
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// 处理消息 }
};
Looper.loop();
}
}
public class Looper {
// 每个线程中的Looper对象其实是一个ThreadLocal,即线程本地存储(TLS)对象
private static final ThreadLocal sThreadLocal = new ThreadLocal();
// Looper内的消息队列
final MessageQueue mQueue;
// 当前线程
Thread mThread;
//其他属性
// 每个Looper对象中有它的消息队列,和它所属的线程
private Looper() {
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
// 我们调用该方法会在调用线程的TLS中创建Looper对象
public static final void prepare() {
if (sThreadLocal.get() != null) {
// 试图在有Looper的线程中再次创建Looper将抛出异常
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
public static final void loop() {
Looper me = myLooper(); //得到当前线程Looper
MessageQueue queue = me.mQueue; //得到当前looper的MQ
// 保证拥有此Looper的线程是本地线程
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
// 开始循环
while (true) {
Message msg = queue.next(); // 取出message
if (msg != null) {
if (msg.target == null) {
// message没有target为结束信号,退出循环
return;
}
// 日志
if (me.mLogging!= null) me.mLogging.println(
">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what
);
// 将Message分发给target-->Handler
msg.target.dispatchMessage(msg);
// 还是日志。。。
if (me.mLogging!= null) me.mLogging.println(
"<<<<< Finished to " + msg.target + " "
+ msg.callback);
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf("Looper", "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
// 回收message资源
msg.recycle();
}
}
}
}