Android Loop&Handle学习总结
来源:互联网 发布:gif调色软件 编辑:程序博客网 时间:2024/05/15 00:23
昨晚偷懒,这篇博客只写了一个标题,今天早晨一看,还有15的阅读量。实在是对不起那些同学.......换了是我,也会BS这样的LZ吧!sorry 啦
-------------------------------------------------------------------------------------------------------------------------------------------------------------
菜鸟我刚刚接触android源码的时候,当时连java语言都不太熟悉(菜鸟我一直是学C/C++),看到android某个应用的源码的时候,曾为这样的代码迷惑过。
private class MainHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case RESTART_PREVIEW: { restartPreview(); if (mJpegPictureCallbackTime != 0) { long now = System.currentTimeMillis(); mJpegCallbackFinishTime = now - mJpegPictureCallbackTime; Log.v(TAG, "mJpegCallbackFinishTime = " + mJpegCallbackFinishTime + "ms"); mJpegPictureCallbackTime = 0; } break; } ...
在同一个文件中不就是想调用restartPreview()函数吗?为什么不直接调用就好,还要发个消息然后在这个handleMessage()中来调用呢?初学菜鸟有没有同样的困惑?还是只有LZ一人太白痴了。
那么到底为什么要这么做呢。是为了异步,是为了多线程,将一些耗时的操作放到一个子线程里面去,大家应该知道如果在android的应用程序主线程,也就是UI线程里面如果执行耗时操作超过5s就会报ANR(application not respon)错误。所以,为了避免ANR,android应用程序将一些耗时操作放到一个独立的工作线程中去。
那么android是如何做到这点的呢?那个新的工作线程又是如何建立的?这就是android中Looper和Handler类的功劳。下面菜鸟来分析下首先看个类图:
从这个图看到Handler和HandlerThread类都有一个Looper成员变量。而且,Handler和Looper都有成员变量MessageQueue,下面我们看看Looper类和Handler类的作用。
Looper:
Looper类,来实现消息循环,内部有一个消息队列。看到Looper类的构造函数是private的,这样外部没法实例化Looper对象,Looper对象的构造只能通过Looper的内部接口,来看一段函数:
/** Initialize the current thread as a looper. * This gives you a chance to create handlers that then reference * this looper, before actually starting the loop. Be sure to call * {@link #loop()} after calling this method, and end it by calling * {@link #quit()}. */ public static final void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper()); } /** Initialize the current thread as a looper, marking it as an application's main * looper. The main looper for your application is created by the Android environment, * so you should never need to call this function yourself. * {@link #prepare()} */ public static final void prepareMainLooper() { prepare(); setMainLooper(myLooper()); if (Process.supportsProcesses()) { myLooper().mQueue.mQuitAllowed = false; } }其中函数prepareMainLooper()函数只在ActivityThread.java的main()函数中被调用过。这个prepareMainLooper()的作用保证每个调用线程都有一个Looper对象,这样应用程序的主线程就有一个Looper对象了,so应用程序主线程的消息循环建立了。
看看,perpare()函数中,有这样一句话 sThreadLocal.set(new Looper());其中sThreadLocal是一个ThreadLocal类型的变量。ThreadLocal表示这是一个线程的局部变量,google之看到下面这段解释。
Implements a thread-local storage, that is, a variable for which each thread has its own value. All threads share the sameThreadLocal
object, but each sees a different value when accessing it, and changes made by one thread do not affect the other threads. The implementation supportsnull
values.
菜鸟斗胆来翻译下,ThreadLocal实现了一种线程的局部存储,ThreadLocal代表一种线程局部变量,对于这种变量来说ThreadLocal保证每个线程都有一个独立的值(value),所有线程都共有一个ThreadLocal对象,但是每个线程在访问这些变量的时候能得到不同的值,每个线程可以更改这些变量并且不会影响其他的线程。ThreadLocal支持NULL值。/*那位大牛有更好的翻译,分享下呗*/
其中ThreadLocal开放了两个接口:
public Tget():获取调用线程的局部变量
public void set(T value) :设置调用线程的局部变量
perpare()函数的这种处理方式保证在每个调用该函数的线程都有一个独立的Looper对象。
Handler:
Handler的作用是处理消息,他封装了消息的投递和对消息的处理。通过上面的图可以看到Handler类有一个Looper和MessageQueue成员变量,Handler类有4个不同的构造函数如下:
public Handler() { 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()); } } /*Handler默认的构造函数,使用当前线程(调用线程)的Looper对象给Handler成员变量mLooper赋值*/ mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } /*使用当前线程(调用线程)的消息队列给Handler的mQueue赋值*/ mQueue = mLooper.mQueue; mCallback = null; } /** * Constructor associates this handler with the queue for the * current thread and takes a callback interface in which you can handle * messages. */ public Handler(Callback callback) { 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; /*跟默认构造函数差不多,只不过带了一个callback*/ mCallback = callback; } /** * Use the provided queue instead of the default one. */ public Handler(Looper looper) { /*使用指定的Looper来给Handler类的mLooper赋值*/ mLooper = looper; mQueue = looper.mQueue; mCallback = null; } /** * Use the provided queue instead of the default one and take a callback * interface in which to handle messages. */ public Handler(Looper looper, Callback callback) { /*使用指定的Looper和CallBack来初始化Handler*/ mLooper = looper; mQueue = looper.mQueue; mCallback = callback; }
可以看到Handler类的成员变量MessageQueue mQueue都会指向Looper类的的MessageQueue,Handler为什么要这么做呢?
下面看看Handler类提供那些接口:
sendEmptyMessage
public final Message obtainMessage(int what) { return Message.obtain(this, what); }/** * Handle system messages here. */ public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }/** * Sends a Message containing only the what value. * * @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 sendEmptyMessage(int what) { return sendEmptyMessageDelayed(what, 0); }/** * Remove any pending posts of messages with code 'what' that are in the * message queue. */ public final void removeMessages(int what) { mQueue.removeMessages(this, what, null, true); } /** *注意这个函数,函数将有子类实现 * Subclasses must implement this to receive messages. */ public void handleMessage(Message msg) { }
其中sendMessage函数都会调用到sendMessageAtTime函数,下面看下sendMessageAtTime(Message msg, long uptimeMillis)函数的实现public boolean sendMessageAtTime(Message msg, long uptimeMillis) { boolean sent = false; MessageQueue queue = mQueue; if (queue != null) { /*看到Message的target变量指向当前这个Handler类*/ msg.target = this; sent = queue.enqueueMessage(msg, uptimeMillis); } else { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); } return sent; }
msg.target指明了这个msg将有谁来处理,在这里msg.target=this,Handler类除了封装消息添加外还封装了消息处理的接口。
Looper和Handler的联系:
本菜鸟不才不知道上面的分析有没有错误,有没有让很多初学者犯迷糊,下面我将分析以下Looper和Handler类的联系,希望可以把上面的知识点串联起来。
当调用Looper类的loop()函数的时候当前线程就进入到一个消息循环中去。看看这个loop()@Looper.java函数先.
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */ public static final void loop() { Looper me = myLooper(); 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(); while (true) { Message msg = queue.next(); // might block //if (!me.mRun) { // break; //} if (msg != null) { if (msg.target == null) { // No target is a magic identifier for the quit message. return; } if (me.mLogging!= null) me.mLogging.println( ">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what ); /*下面的函数将Looper类和Handler类联系起来*/ msg.target.dispatchMessage(msg); if (me.mLogging!= null) me.mLogging.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("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); } msg.recycle(); } } }
可以看到当前线程不断的从消息队列中取出消息,如果消息的target成员变量为null,就表示要退出消息循环了,否则的话就要调用这个target对象的dispatchMessage成员函数来处理这个消息,这个target对象的类型为Handler。
其实这个Looper和Handler类中消息传递的机制还是很复杂到,用到了Linux中Pipe的相关知识,我太菜还不能做出更深的分析,以后有时间会好好学习下,在完善下这部份的知识。
好了,这篇blog就说到这里吧。下篇blog我会试着分析下,Handler和Looper的同步问题。届时会顺便学习一下HandlerThread类。
忘了说,如果哪位大牛发现我这篇blog有什么错误,敬请指正,免得误导了跟我一样的菜鸟
- Android Loop&Handle学习总结
- LOOP & HANDLE
- Android中Handle总结
- Android中Handle总结
- Android-Handle类总结
- android handle学习笔记
- Android学习之Handle
- Android中handle用法总结
- IOS-Run loop学习总结
- Android Thread,Handler,Loop,Message,HandlerThread总结
- android handle
- android handle
- android handle
- android---handle
- android Handle
- Android Handle
- android Handle
- android学习--消息机制Handler Loop MesssageQueue
- 聊天气泡sms
- ChartDirector 5.0 for python 笔记【4】Multi-Depth Pie Chart
- SearchBar深度解析--这个比较早了 最近版sdk 有的方法不能用了 参考下吧
- OpenFlow(效果图)中文实用详解
- 简单号码分配器的实现分析
- Android Loop&Handle学习总结
- 改变键盘的颜色
- 黑马程序员_String类
- NSNavgationController自定义切换画面(传送参数)
- UItableView实现分页效果(点击more再显示10条)
- 允许对cell进行编辑和拖动
- android手机之间用wifi direct通信
- !!!!!!!!!!!
- UIimage的缩放线程实现安全和非线程安全操作