从源码角度看Handler原理
2015-10-20 00:00
459 查看
在Android中,有一个规定就是除了主线程,其他线程不能操作UI视图,因为不这样做的话会出现线程不安全问题。但还有一个规定UI线程在执行一个操作如果5秒内没有响应就会包ANR错误。所以UI线程中不允许访问网络这样的耗时操作,那么问题来了,子线程执行耗时操作,比如从网络获取图片,但子线程不能更新UI,而主线程能更新UI,但不能去下载图片。这样handler消息处理机制就出现了。
Message:对发送的消息的封装
MessageQueue:消息队列,存放所有的消息
Looper:可以循环读取消息(从MessageQueue中读取)
Handler:处理消息,同时也是发送消息的
具体来看看handler是怎么实现的。
4.1使用1:主线程接收子线程发来的消息(下载图片为例)
1)在主线程中初始化handler对象:
2)然后子线程中下载好图片后发送图片给主线程:
消息的拦截:
3)使用1有关handler机制的操作有:
Handler handler = new Handler();
handleMessage(Message msg);
Message msg = Message.obtain();
handler.sendMessage(msg);
那么现在来看一看它内部到底是怎样执行的。
这个无参构造方法会调用两个参数的构造方法,注意上面的参数null和false,如下:
那来看看这个两个参数的构造方法都做了些什么。
FIND_POTENTIAL_LEAKS这个变量初始化为false
private static final boolean FIND_POTENTIAL_LEAKS = false;
所以直接执行后面的,也就是这些:
这几句的操作就是得到一个Looper对象和一个MessageQueue对象,mLooper = Looper.myLooper();中Looper.myLooper()方法中是得到当前线程的Looper对象。那么当前线程是什么?在这里,因为我们是在主线程中实例化Handler对象,所以当前线程就是主线程,值得注意的是,主线程在创建时就会维护一个Looper对象和MessageQueue对象,所以这里得到的Looper对象和消息队列都是主线程的。
mQueue = mLooper.mQueue;这句说明handler内部的MessageQueue和Looper的MessageQueue是一个。
好,那么handler的初始化阶段先到这里。
5.2 Message msg = Message.obtain();
再来看看这句做了哪些事,
注意:有时候我们会直接这么写Message msg = new Message();
这里的意思就是如果sPool不为空就返回sPool,否则就new一个新的Message对象。(sPool是回收放在消息池中的对象)
5.3 handler.sendMessage(msg);
关键的一句终于到了,来看看这个又做了什么。
第一步:
第二步:
第三步:
第四步:
到第四步算是找到能办事的了,看这里都办了哪些事。
1) msg.target = this;可以查看Message源码target就是Handler类型的,这里把msg的target指向this,也就是这个发送消息的handler。
2)queue.enqueueMessage(msg, uptimeMillis);调用queue的enqueueMessage方法,去MessageQueue类中看看。
很简单,就是把handler发送的msg加入到消息队列中。
5.4handleMessage(Message msg);
好了,最后只用处理msg了。这是个回调方法,所以必须要等到Looper去从消息队列中读取消息时才会执行。
那就去看看Looper.loop();这个循环读取消息的方法。
开头几句是得到当前线程的Looper对象,然后同构Looper对象得到queue对象,很明显,5.1已经说了,那么这里得到的就是主线程那个Looper和MessageQueue。然后开始了死循环,一直从消息队列中读取消息,读不到就返回,否则执行后面操作。注意看后面操作,真正处理消息的时候到了。
msg.target.dispatchMessage(msg);关键就是这句。 它调用了msg的target的dispatchMessage方法,之前说了,target就是发送消息的那个handler,好,再会Handler类看dispatchMessage方法。
很简单,这就是一个消息分发处理嘛。记得handler发送消息有两种方式,一种就是普通的handler.sendMessage(msg);方法,还有一种就是
handler.post(new Runnable(){
@Override
public void run() {
//主线程应该执行的操作
}
});
先来看第一种:直接回调hanleMessage(msg);方法,这样主程序中就执行该操作啦。
再来看第二种:
调用message.callback的run方法。
从源码可以一步一步看出,如下,message的callback指向handler调用post方法传入的Runnable对象。
再回头看dispatchMessage方法,会调用下面这个方法:
内部最后调用run方法。
handler原理基本就这样了。
总结:handler对象定义在需要接收本线程或其他线程发送消息的线程中,该线程会维护一个Looper对象和MessageQueue对象,在其他线程或本线程通过handler发送的消息会加入到handler所在线程中的消息队列中,同时Looper的loop()方法会一直读取消息队列,读到消息后,又让发送消息的handler处理这个消息。
1. Handler是什么?
handler是Android给我们提供用来更新UI的一套机制,也是一套消息处理的机制,我们可以发送消息,也可以通过它处理消息。2. 为什么要使用Handler?
Android在设计时,就封装了一套消息消息创建、传递、处理机制,如果不遵循这样的机制就没办法更新UI,就会抛出异常。3. Android中为什么要设计只能通过Handler机制更新UI?
解决多线程并发问题。如果允许多线程更新UI会导致界面错乱,如果非要使用多线程并使用加锁机制更新UI又会导致性能下降,所以更新UI的操作全部交给主线程。4.那么handler机制是怎样的机制呢?
了解handler机制,首先需要清楚四个核心类:Message:对发送的消息的封装
MessageQueue:消息队列,存放所有的消息
Looper:可以循环读取消息(从MessageQueue中读取)
Handler:处理消息,同时也是发送消息的
具体来看看handler是怎么实现的。
4.1使用1:主线程接收子线程发来的消息(下载图片为例)
1)在主线程中初始化handler对象:
private Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { //处理子线程发送过来的message Bitmap bitmap = (Bitmap)msg.obj; imageView.setImageBitmap(bitmap); } };
2)然后子线程中下载好图片后发送图片给主线程:
new Thread(new Runnable() { @Override public void run() { HttpGet get = new HttpGet(path); HttpClient client = new DefaultHttpClient(); HttpResponse response = null; try { response = client.execute(get); if (response.getStatusLine().getStatusCode() == 200) { byte[] arr = EntityUtils.toByteArray(response .getEntity()); Bitmap bitmap = BitmapFactory.decodeByteArray(arr, 0, arr.length); // 下载完成时把图片发送给主线程 // 从MessageQueue中获取可用的Message对象,如果没有可用的Message对象则会创建一个新的Message对象 Message msg = Message.obtain(); // 把发送的图片封装到msg中 msg.obj = bitmap; // 使用Handler发送msg handler.sendMessage(msg);// 把msg发送给实例化handler的线程 } } catch (Exception e) { e.printStackTrace(); } } }).start();
消息的拦截:
/** * 拦截消息测试 * @author Administrator * */ public class ThirdActivity extends Activity { Handler handler = new Handler(new Callback() { @Override public boolean handleMessage(Message msg) { Log.i("--", "消息都要经过我这里"); /**返回false,消息会继续向下分发,返回true则拦截*/ return true; } }) { @Override public void handleMessage(Message msg) { super.handleMessage(msg); Log.i("--", "我才是处理消息的"); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new Thread(new Runnable() { @Override public void run() { handler.sendEmptyMessage(1); } }).start(); } }
3)使用1有关handler机制的操作有:
Handler handler = new Handler();
handleMessage(Message msg);
Message msg = Message.obtain();
handler.sendMessage(msg);
那么现在来看一看它内部到底是怎样执行的。
5.从源码一步一步分析handler原理
5.1Handler handler = new Handler();public Handler() { this(null, false); }
这个无参构造方法会调用两个参数的构造方法,注意上面的参数null和false,如下:
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; }
那来看看这个两个参数的构造方法都做了些什么。
FIND_POTENTIAL_LEAKS这个变量初始化为false
private static final boolean FIND_POTENTIAL_LEAKS = false;
所以直接执行后面的,也就是这些:
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;
这几句的操作就是得到一个Looper对象和一个MessageQueue对象,mLooper = Looper.myLooper();中Looper.myLooper()方法中是得到当前线程的Looper对象。那么当前线程是什么?在这里,因为我们是在主线程中实例化Handler对象,所以当前线程就是主线程,值得注意的是,主线程在创建时就会维护一个Looper对象和MessageQueue对象,所以这里得到的Looper对象和消息队列都是主线程的。
public static Looper myLooper() { return sThreadLocal.get(); }
mQueue = mLooper.mQueue;这句说明handler内部的MessageQueue和Looper的MessageQueue是一个。
好,那么handler的初始化阶段先到这里。
5.2 Message msg = Message.obtain();
再来看看这句做了哪些事,
注意:有时候我们会直接这么写Message msg = new Message();
public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; sPoolSize--; return m; } } return new Message(); }
这里的意思就是如果sPool不为空就返回sPool,否则就new一个新的Message对象。(sPool是回收放在消息池中的对象)
public void recycle() { clearForRecycle(); synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } }
5.3 handler.sendMessage(msg);
关键的一句终于到了,来看看这个又做了什么。
第一步:
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); }
到第四步算是找到能办事的了,看这里都办了哪些事。
1) msg.target = this;可以查看Message源码target就是Handler类型的,这里把msg的target指向this,也就是这个发送消息的handler。
2)queue.enqueueMessage(msg, uptimeMillis);调用queue的enqueueMessage方法,去MessageQueue类中看看。
final boolean enqueueMessage(Message msg, long when) { if (msg.isInUse()) { throw new AndroidRuntimeException(msg + " This message is already in use."); } if (msg.target == null) { throw new AndroidRuntimeException("Message must have a target."); } boolean needWake; synchronized (this) { if (mQuiting) { RuntimeException e = new RuntimeException( msg.target + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); return false; } msg.when = when; Message p = mMessages; if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; needWake = mBlocked; } else { // Inserted within the middle of the queue. Usually we don't have to wake // up the event queue unless there is a barrier at the head of the queue // and the message is the earliest asynchronous message in the queue. needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; for (;;) { prev = p; p = p.next; if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; } } msg.next = p; // invariant: p == prev.next prev.next = msg; } } if (needWake) { nativeWake(mPtr); } return true; }
很简单,就是把handler发送的msg加入到消息队列中。
5.4handleMessage(Message msg);
好了,最后只用处理msg了。这是个回调方法,所以必须要等到Looper去从消息队列中读取消息时才会执行。
那就去看看Looper.loop();这个循环读取消息的方法。
public static void loop() { final Looper me = myLooper(); if (me == null) { 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; } // 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); 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(); } }
开头几句是得到当前线程的Looper对象,然后同构Looper对象得到queue对象,很明显,5.1已经说了,那么这里得到的就是主线程那个Looper和MessageQueue。然后开始了死循环,一直从消息队列中读取消息,读不到就返回,否则执行后面操作。注意看后面操作,真正处理消息的时候到了。
msg.target.dispatchMessage(msg);关键就是这句。 它调用了msg的target的dispatchMessage方法,之前说了,target就是发送消息的那个handler,好,再会Handler类看dispatchMessage方法。
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
很简单,这就是一个消息分发处理嘛。记得handler发送消息有两种方式,一种就是普通的handler.sendMessage(msg);方法,还有一种就是
handler.post(new Runnable(){
@Override
public void run() {
//主线程应该执行的操作
}
});
先来看第一种:直接回调hanleMessage(msg);方法,这样主程序中就执行该操作啦。
再来看第二种:
private static void handleCallback(Message message) { message.callback.run(); }
调用message.callback的run方法。
从源码可以一步一步看出,如下,message的callback指向handler调用post方法传入的Runnable对象。
private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
再回头看dispatchMessage方法,会调用下面这个方法:
private static void handleCallback(Message message) { message.callback.run(); }
内部最后调用run方法。
handler原理基本就这样了。
总结:handler对象定义在需要接收本线程或其他线程发送消息的线程中,该线程会维护一个Looper对象和MessageQueue对象,在其他线程或本线程通过handler发送的消息会加入到handler所在线程中的消息队列中,同时Looper的loop()方法会一直读取消息队列,读到消息后,又让发送消息的handler处理这个消息。
源码下载
版权声明:本文为博主原创文章,未经博主允许不得转载。相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories