Android中的handler
来源:互联网 发布:网络电视怎么看中央8吗 编辑:程序博客网 时间:2024/05/16 05:31
首先先看一下android中的线程基本使用方式:
1. 继承Thread方式:复写run()方法
2. 实现Runnable方式 接口:传给Thread :new Thread(newplaybackRunnable()).start();
以上两种方法殊归同途,都是在新线程中调用用户实现run方法(方式上还是有区别的,需要可以查看资料,在我的搜藏中也有)。
下面我们来关注下android中的hanlder机制。handler主要的用途就是提供一个消息机制,可以方便地在一个消息循环线程中实现消息的处理,无论是在本线程还是在其他线程。不过,首先需要保证线程是有消息循环的。android中的UI线程都是由消息循环的。
来看一下handler机制三个相关的类:Handler, Message, Looper
首先来看下Looper类:它的构造函数是私有的,可见不能在外部创建。唯一创建的地方:
public static void prepare() { prepare(true); }
private static void prepare(boolean quitAllowed) {if (sThreadLocal.get() != null) {thrownewRuntimeException("Only one Looper may be created per thread"); }sThreadLocal.set(new Looper(quitAllowed)); }
此处创建了,就把它设置到ThreadLocal中。
再来看看Looper构造函数都干了什么:
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mRun = true; mThread = Thread.currentThread(); }
它创建了一个消息队列,又结合上面的prepare函数,可见Looper实例在一个Thread中使唯一的,进而消息队列也是唯一的。
然后是loop的主循环体:它不停地从消息队列中取出消息来处理。
public static void loop() { final Looper me = myLooper();//note how find the Looper 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(); } }
这里注意消息队列的获得,来看mylooper函数:
public static Looper myLooper() { return sThreadLocal.get();}
可见,要想消息循环,之前必须要构造出looper实例,并放入到ThreadLocal中。这里,looper已经处理好了,是要调用上面的prepare函数,切忌!
然后就是消息如何处理了,可以看到,最主要的就是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); } }
从上就看到了处理消息的三种方式:
1. 调用消息的callback
2. 调用Hanlder的callback
3. 调用handler的handleMessage
再来看看Handler:
Handler总体来说有两种构造方式:
1. 不带looper的构造方式:
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;} }
2. 带looper的构造方式:
public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async;}
不带looper的构造方式将获得本线程的Queue,带looper的构造方式,获得的是looper的Queue.这为之后handler跑在哪个线程上打上了伏笔。
最后看看Message:
Message的构造大体分为三种:
1. 不带handler和callback的构造:
public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; sPoolSize--; return m; } } return new Message();}
此时target为null
2. 带参数Handler的构造:
public static Message obtain(Handler h) { Message m = obtain(); m.target = h; return m; }
此时target为传入的handler
3. 带handler和callback的构造:
public static Message obtain(Handler h, Runnable callback) { Message m = obtain(); m.target = h; m.callback = callback; return m; }
有了以上这些基础,我们再来看看消息handler机制是如何使用的:
有几种方式:
1. 直接获取message,然后传给handler处理:
Msg = Message.obtain();Handler.sendMessage(msg);
这里可以跟踪Handler.sendMessage(msg),最后走到:
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); }
可以看到,以上将msg入队到自己的queue中,最后就到了queue的线程中去处理了:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis);}
注意这里msg.target =this;所以无论消息有没有设置target,只要调用了Handler的SendMessage,它的处理就绑定到了handler上了。
Ok ! 这种方式是跑在handler的线程中的,至于handler值跑在哪个线程中,看看上面handler的两种构造函数就知道了。
2. 通过hanlder来获得Message:
class Handler{
public final Message obtainMessage(){ return Message.obtain(this);}
}
可见最后调用的还是消息的obtain(Hanlder)函数。还是在handler的handleMessage中处理。
3. 通过handler的post方式:
Handler. post(Runnable r): { return sendMessageDelayed(getPostMessage(r), 0);}
private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
最后还是在handler的线程中,处理的是runnable接口的实现。
4. 通过message的SendToTarget的方式:
Message.sendToTarget(): public void sendToTarget() { target.sendMessage(this);}
可见这个是在与message关联的handler中处理的。注:处理之前message一定要有与之关联的target(Hanlder),也就是message的获得一定通过有handler的方式获得,或者之后要手动设置下handler,不然会因为找不到target而出错。
好了,以上4种大概就是我们一般使用handler消息机制的一般方式。
总结:
1. Looper不用用户操心,但是构造消息循环线程的话,一定要Looper.prepare()一下,以用来创建本地消息队列。
2. handler的两种构造方式决定了handler是在哪个线程上被处理的。 这里要注意:如果hanlder在本地线程上处理,则本地线程一定要有handler机制,也就是消息循环系统。不然handler会因为找不到Looper而出错!
3. Message的获取方式决定了消息的处理是在哪个函数中进行的(参考上面dispatchmessage处理)。 为消息的处理提供了多种方便的方式(参考Message的构造方式一节)。
最后来看下HandlerThread:
public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; }
这个类为我们提供了一个消息循环线程的所有工作,我们只要在这个线程上处理消息就可以了。
调用此类的getLooper可以得到looper,然后用它来构造hanlder就可以发送消息到这个线程来处理了。
- Android中的Handler
- android中的handler例
- Android中的Handler总结
- Android中的Handler总结
- Android中的handler
- Android中的Handler总结
- Android中的Handler机制
- Android中的Handler总结
- Android中的Handler总结
- Android中的Handler总结
- Android中的Handler总结
- 理解android中的handler
- android中的handler
- Android中的Handler总结
- Android中的Handler总结
- Android中的Handler总结
- android中的handler
- Android中的Handler
- Django- 从零开始
- Java基础知识_反射
- 线程空间优化
- Unity 下载资源包
- 浅谈HTTP中get和post的区别
- Android中的handler
- 文件包含#include
- 数据切分与合并框架收集
- Matlab学习
- Win64+OpenCV2.3.1+Python2.7.5配置
- 【高斯消元应用】hdu3949
- miller素数测试
- Windows 7 home base打开administrator的操作
- 手把手教你在Ubuntu上安装Apache、MySql和PHP