Android中异步任务用法(即另起一工作线程去完成耗时操作),非常常见。我们要加载图片,需要异步任务;我们要网络请求,需要异步任务;我们要读写数据库,需要异步任务;当然现在我们用的比较多的是Asynctask。但是其本质也是对Handler,Looper,Message的封装。所以我要求自己必须,对Handler,Message,Looper的运行机制熟悉透彻,在这里做些笔记,加深印象!
1,Looper:
public class Looper {
private static final String TAG = "Looper";
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
volatile boolean mRun;
private Printer mLogging;
这是looper的类,我们可以看到Looper对象中:
有一个MessageQueue消息队列;
有ThreadLocal<Looper> 一般用于为本线程绑定唯一对象;
有Thread线程对象。
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
上面是Looper的prepare()方法。
sThreadLocal.get()!=null;即线程中已经存在了Looper对象,则报异常。因此表明Looper对象是单例的,prepare()方法只能调用一次;如果是首次执行,则将Looper绑定到当前线程。
public static void loop() {
final Looper me = myLooper();//myLooper方法的源码在下面,返回本线程绑定的Looper对象
if (me == null) { //如果为null表示没有绑定Looper对象,报异常,也就是说loop()前,必须调用prepare()方法。
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;//获的消息队列
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {//进入无限循环,
Message msg = queue.next(); // might block
if (msg == null) { //不断地从消息队列中获取消息对象
// No message indicates that the message queue is quitting.
return;//这个逻辑大家是不是有疑问:刚开始没有消息时,不就退出循环了?其实大家看一下MessageQueue的next()方法就知道了这个方法也是有一个无限循环。拿到消息对象,或者因为其他不可逆的错误,才结束有返回值。}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);//拿到消息后执行的方法,后面大家就会知道meg.target就是发送消息的Handler对象。
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "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);
}
msg.recycle();//释放资源
}
}
public static Looper myLooper() {
return sThreadLocal.get();
}
Looper的另一个重要方法loop();注解写在代码里面了!
Looper的主要作用:1,与当前线程绑定,保证只有一个Looper对象,也只有一个MessageQueue对象
2,loop()方法不断从MessageQueue中获取消息,并交给message的Target的DispatchMessage()方法处理。
2,Handler
public Handler(boolean async) {
this(null, async);
}
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
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;
mAsynchronous = async;
}
从Handler的构造方法中我们可以看到:
1,Handler类中有与当前线程绑定的Looper对象
2,自然也有与Looper对象对应的MessageQueue消息队列
那么Handler的sendMessage发送消息的方法其实就是在MessageQueue存放消息,就变得很简单!
我们还是跟踪一下最常用的sendMessage()。
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);//存放消息的代码在MessageQueue中
}
到了这里:msg.target=this;这个this自然就是Handler,上面的Looper对象的Loop()方法中,处理消息的代码是:
msg.target.dispatchMessage(msg);大家应该明白调用的是Handler的dispatchMessage(msg)方法。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
handleMessage(msg)终于出现了!
到了这里可以做一个小结了:
1,Looper.prepare()方法,在本线程中绑定一个Looper实例,Looper实例中绑定一个MessageQueue;Looper对象是单例的。
2,Looper.loop();在本线程中执行一段无限循环代码,不断地从MessageQueue中,获取Message,调用Message.target.dispatchMessage()方法进行处理。
3,Handler的构造方法中,获得与本线程绑定的Looper对象,以及对应的MessageQueue消息队列。
4,Handler的sendMessage将Message对象的target属性设为自身,并放入MessageQueue消息队列。
5,回调Handler的dispatchMessage方法,执行我们重写的handleMessage()方法。
Handler的另一种应用:
handler.post(new Runnable() {
@Override
public void run() {
Log.i("www","i am in runnable" );
}
});
通常在工作线程中,可以直接调用工作线程中的局部变量。我们跟踪。
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
</pre><pre name="code" class="java">private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;//这里与Handler的sendMessage的不同处,为message的callback属性赋值r;
return m;
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
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);
}
最终的差异体现在:这边执行的是handleCallback(msg);方法
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
最终还是执行的Runnable的run方法。