安卓Handler详解
来源:互联网 发布:阿里云怎么赚钱 编辑:程序博客网 时间:2024/06/08 00:28
在安卓中由于主线程中不能进行耗时操作,我们往往需要另外开启一个线程来进行耗时操作,操作完成之后,我们通常需要使用Handler来将结果展现在界面中,下面我来说明下handler的使用。
Handler的创建
public Handler mHandler = new Handler();
Handler的创建只要new 一个Handler的对象就可以了,那么新建一个对象,系统究竟做了什么呢?
public Handler() { this(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; }其中最重要的就是
mLooper = Looper.myLooper();if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()");}mQueue = mLooper.mQueue;mQueue是MessageQueue类的一个对象,是一个消息队列,主要的作用就是储存由一个线程发送到主线程的消息,而Looper则是用来对MessageQueue来进行管理。
如果在该线程中没有Looper类,则会报错
if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); }在Activity中,由系统自动给我们创建Looper。
Handler其实也可以创建在非主线程中,前提是在非主线程中,我们手动的创建Looper,即调用Looper.prepare()方法。
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呢,这要通过sThreadLocal来实现
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public void set(T value) { Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values == null) { values = initializeValues(currentThread); } values.put(this, value); }public T get() { // Optimized for the fast path. Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values != null) { Object[] table = values.table; int index = hash & values.mask; if (this.reference == table[index]) { return (T) table[index + 1]; } } else { values = initializeValues(currentThread); } return (T) values.getAfterMiss(this); }上面就是ThreadLocal的get和set方法,简单点说就是将Looper与创建Looper的线程采用一一对应的关系保存起来,以此来确保在一个线程中只有一个Looper。
就是说如果在一个线程中创建了多个Looper,则会报错,并提示Only one Looper may be created per thread,如果在该线程中没有创建过Looper,则新建一个Looper
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
由他的构造方法可以看到,创建Looper的同时,系统会创建MessageQueue对象,这个对象也就是上面提到的Handler创建时的那个MessageQueue对象,所以在一个线程中只有一个Looper,也即只有一个MessageQueue对象,但是需要注意的是可以有多个Handler对象,那怎么确保由正确的Handler对象处理由其发送的Message呢,我们接着看源码。
在子线程中我们一般都是调用Handler的sendMessage方法发送消息,其实Handler的发送消息的方法,包括sendMessage,sendEmptyMessage,sendEmptyMessageDelayed等经过处理,最终都会调用下面这个方法
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); }可以看到,在enqueueMessage方法中msg.target的值为this,也就是这个Handler对象本身,就是说只要有这个message,就可以通过target这个参数知道是有谁发送的,所以就解决了上面关于如果有多个Handler怎么正确处理消息的问题。
现在完成了消息的发送。
下面我们看下怎么处理消息。
Looper的创建一般包括两部分,一个是Looper.prepare(),我们上面已经说过了,还有一个就是Looper.loop(),这个loop就是取消息,函数中会有一个死循环,不停地从MessageQueue中获取消息,即获取我们发送的Message对象,再通过Message中的target也就是发送消息的Handler对象的handMessage方法实现回调,完成从一个线程发送消息到另一个线程。
需要注意的是在loop方法中他会有一个类似锁的机制,即当MessageQueue中没有消息的时候,程序会阻塞在消息队列中,由于Looper是创建在主线程中,也就是说主线程此时是阻塞的。
我查了一些资料我觉得其中比较靠谱的一种说法是这样的:系统它本身也是通过Handler这种方法实现刷新UI的,而且系统刷新的时间是很快的,每16ms都要进行一次刷新,所以Looper顶多也就阻塞十几毫秒左右,并不会造成系统的ANR。这只是我的认识,欢迎指正
- 安卓handler详解
- 安卓Handler详解
- 安卓msg handler looper详解
- 安卓中的消息循环机制Handler及Looper详解
- 安卓Handler实例
- 安卓 Handler使用方法
- 安卓handler释义
- 安卓handler学习
- 安卓handler
- 安卓学习-Handler
- 安卓学习-Handler
- 安卓Handler机制
- 安卓倒计时(android.os.Handler.Handler()
- 安卓开发-Handler学习
- 安卓Handler消息机制
- 关于安卓中的Handler
- 安卓Handler类介绍
- 安卓:handler的基础
- CSP的今世与未来
- 关于MAVEN 问题
- C++中#pragma pack(N)的用法
- OpenOrCreateDatabase与SQLiteOpenHelper区别
- javaScript JSON
- 安卓Handler详解
- jsp获得BASEURL
- android的消息处理机制——Looper,Handler,Message
- redis学习 第三章 5种数据类型----sorted set类型
- c++系列文章序
- 2016区域赛前补题训练
- 计算字符串种子串出现的个数
- Android View 和 ViewGroup 事件分发机制
- 设计模式-工程模式