Hanlder的使用方式一:
1 private static Handler mHandler = new Handler(){ 2 public void handleMessage(android.os.Message msg) { 3 switch (msg.what) { 4 case ONE: 5 6 break; 7 8 default: 9 break; 10 } 11 }; 12 };
Handler的使用方式二:
1 public void startHandlerThread(){ 2 HandlerThread mHandlerThread = new HandlerThread("TestHandler"); 3 mHandlerThread.start(); 4 Handler mHandler = new Handler(mHandlerThread.getLooper()){ 5 @Override 6 public void handleMessage(Message msg) { 7 // TODO Auto-generated method stub 8 super.handleMessage(msg); 9 } 10 }; 11 }
第二种比较通用,为什么这么说类,原因就是HandlerTrehad是个Thread,在run方法内部已经完成了Looper.prepare()的方法的调用,所以即使在子线程中也不会有任何问题
基本的使用就暂时说这些!!!!!
进入咱们今天的正题,深入裙内分析Handler源码:
1 /** 2 * Sends a Message containing only the what value. 3 * 4 * @return Returns true if the message was successfully placed in to the 5 * message queue. Returns false on failure, usually because the 6 * looper processing the message queue is exiting. 7 */ 8 public final boolean sendEmptyMessage(int what) 9 { 10 return sendEmptyMessageDelayed(what, 0); 11 }
关于sendMessage就暂时拿这个进入问题内部;
Line10:说的很明确,调用delay方法,传入delay事件零毫秒,在跟进一步
1 /** 2 * Sends a Message containing only the what value, to be delivered 3 * after the specified amount of time elapses. 4 * @see #sendMessageDelayed(android.os.Message, long) 5 * 6 * @return Returns true if the message was successfully placed in to the 7 * message queue. Returns false on failure, usually because the 8 * looper processing the message queue is exiting. 9 */ 10 public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { 11 Message msg = Message.obtain(); 12 msg.what = what; 13 return sendMessageDelayed(msg, delayMillis); 14 }
这个方法为每个Handler消息进行封装一个Message对象,然后继续调用delay方法,但是这个方法的参数和之前的不一样,不通点就是接受一个Mesage对象,和一个延迟的时间。
Line11:从缓存中读取Mesage对象,如果没有则直接创建;
Line12,绑定What,回头再handlerMessage()方法中要用到;充当Swith的case;
继续深入:
1 public final boolean sendMessageDelayed(Message msg, long delayMillis) 2 { 3 if (delayMillis < 0) { 4 delayMillis = 0; 5 } 6 return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); 7 }
该出进行了容错处理防止你瞎传值;
然后调用方法sendMessageAtTime这里的参数需要说明下:为什么SystemClock.uptimeMillis() + delayMillis这块的意思是加当当前系统时间,其实意思很明显如果你的延迟时间是一秒,那么这个一一秒的起始点,自然就是从当前算起,不然你仅仅说一秒,那么从什么时候开始那,这里就是这个意思了!!!
来继续看方法sendMessageAtTime
1 public boolean sendMessageAtTime(Message msg, long uptimeMillis) 2 { 3 boolean sent = false; 4 MessageQueue queue = mQueue; 5 if (queue != null) { 6 msg.target = this; 7 sent = queue.enqueueMessage(msg, uptimeMillis); 8 } 9 else { 10 RuntimeException e = new RuntimeException( 11 this + " sendMessageAtTime() called with no mQueue"); 12 Log.w("Looper", e.getMessage(), e); 13 } 14 return sent; 15 }
这个是Message入队的操作,看代码,既然说到入队,那么自然就少不了需要队列来存储这个Message,Line4,得到这个消息队列。然后准备入队;
Line6:这个操作很重要,为什么要交付这个Targe,因为这里在出队列的时候要用到,出队后要调用handlermessge方法,进行消息处理,如何调用handlemessge方法,在Android的世界里基本就是指对象,很显然这里targe指向了当前对象this;(不懂没关系,后边会在补充讲解)
Line7:进行入队操作,返回入队的最终结果,如果是true则代表成功入队,否则为失败;
1 final boolean enqueueMessage(Message msg, long when) { 2 if (msg.when != 0) { 3 throw new AndroidRuntimeException(msg 4 + " This message is already in use."); 5 } 6 if (msg.target == null && !mQuitAllowed) { 7 throw new RuntimeException("Main thread not allowed to quit"); 8 } 9 final boolean needWake; 10 synchronized (this) { 11 if (mQuiting) { 12 RuntimeException e = new RuntimeException( 13 msg.target + " sending message to a Handler on a dead thread"); 14 Log.w("MessageQueue", e.getMessage(), e); 15 return false; 16 } else if (msg.target == null) { 17 mQuiting = true; 18 } 19 20 msg.when = when; 21 //Log.d("MessageQueue", "Enqueing: " + msg); 22 Message p = mMessages; 23 if (p == null || when == 0 || when < p.when) { 24 msg.next = p; 25 mMessages = msg; 26 needWake = mBlocked; // new head, might need to wake up 27 } else { 28 Message prev = null; 29 while (p != null && p.when <= when) { 30 prev = p; 31 p = p.next; 32 } 33 msg.next = prev.next; 34 prev.next = msg; 35 needWake = false; // still waiting on head, no need to wake up 36 } 37 } 38 if (needWake) { 39 nativeWake(mPtr); 40 } 41 return true; 42 }
Line2 Line6很显然如果这两个对象为Null则直接就是throw exception;为什么这样那????因为这handler必须的两个字段。
时间:标记何事处理这个Message;
Target:应该由谁来处理;
两者缺一不可,否则Handler就不是Handler了。。。。。。。
核心代码Line20--36
1 ................ 2 msg.when = when; 3 //Log.d("MessageQueue", "Enqueing: " + msg); 4 Message p = mMessages; 5 if (p == null || when == 0 || when < p.when) { 6 msg.next = p; 7 mMessages = msg; 8 needWake = mBlocked; // new head, might need to wake up 9 } else { 10 Message prev = null; 11 while (p != null && p.when <= when) { 12 prev = p; 13 p = p.next; 14 } 15 msg.next = prev.next; 16 prev.next = msg; 17 needWake = false; // still waiting on head, no need to wake up 18 } 19 ...................
Line5的判断是拿当前即将进行出队的Message的when做对比,如果你的时间小(也就是你应该被优先出队),那么久交换当前的出队对象,很显然,现在Message就在事队列的最前端,等出队的时间到了就执行出队操作。
Line9,这是入队操作不同点就是需要执行插入的操作,为什么要插入哪?因为Message的排序是按照When来排序的谁的When小谁在前边,这样出队就不会出错,保证出队的有序性。首先声明一个temp变量prev,然后从队列的首位置开始,根据时间when的大小进行比较,如果找到合适的就交换交换类似C中的指针方式。建议大家绘制个草图,可以很明显的看出交换过程!
到了这里Message就完成了入队的操作,在整个入队的操作大家是否注意到一个问题,MessageQueu怎么出现的!!!!!
<:>讲述Message的初始化代码:
说先追根溯源,第一次使用的地方就是Handler中,很好咱们就从这里入手吧!!!
1 public Handler() { 2 if (FIND_POTENTIAL_LEAKS) { 3 final Class<? extends Handler> klass = getClass(); 4 if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && 5 (klass.getModifiers() & Modifier.STATIC) == 0) { 6 Log.w(TAG, "The following Handler class should be static or leaks might occur: " + 7 klass.getCanonicalName()); 8 } 9 } 10 11 mLooper = Looper.myLooper(); 12 if (mLooper == null) { 13 throw new RuntimeException( 14 "Can't create handler inside thread that has not called Looper.prepare()"); 15 } 16 mQueue = mLooper.mQueue; 17 mCallback = null; 18 }
Line 16进行赋值 的操作,很显然最初的创建位置并不是这里,这里只是通过looper对象得到的改队列的引用,而并不是在这里进行了Create.
Line 11这里有说道搞Looper对象的获取,既然咱们是通过Looper对象获取的队列对象,那么是不是咱们可以进入这个类看下原因为几何???
1 private Looper() { 2 mQueue = new MessageQueue(); 3 mRun = true; 4 mThread = Thread.currentThread(); 5 }
Line2说明这个问题,Looper对象创建的时候,初始化了这个MessageQueue.
<>><>到这里基本咱们说完了怎么入队,以及队列的由来,那么接下来就看怎么出队的操作!!!!
说道出队,自然就说到咱们的《Looper,轮询器》
既然Looper是轮询器,那么根据java面向对象的思想,这里自然就会偶轮训的方法loop;
<<<<<果不其然>>>>>
1 /** 2 * Run the message queue in this thread. Be sure to call 3 * {@link #quit()} to end the loop. 4 */ 5 public static final void loop() { 6 Looper me = myLooper(); 7 MessageQueue queue = me.mQueue; 8 while (true) { 9 Message msg = queue.next(); // might block 10 //if (!me.mRun) { 11 // break; 12 //} 13 if (msg != null) { 14 if (msg.target == null) { 15 // No target is a magic identifier for the quit message. 16 return; 17 } 18 if (me.mLogging!= null) me.mLogging.println( 19 ">>>>> Dispatching to " + msg.target + " " 20 + msg.callback + ": " + msg.what 21 ); 22 msg.target.dispatchMessage(msg); 23 if (me.mLogging!= null) me.mLogging.println( 24 "<<<<< Finished to " + msg.target + " " 25 + msg.callback); 26 msg.recycle(); 27 } 28 } 29 }
代码484很少,哈哈哈哈,开森死人了、、、、、
直奔主题走;Line22;这个Targe大家还记得不,(忘了去前边再去复习,真都比)上边说到这个是Handler对象,那么这里调用的方法dispatchMessage进行的Message的分发操作,自然分发最后还是交给了Handler,一起看下咱们说的队不对吧,去Handler找下这个方法????
1 /** 2 * Handle system messages here. 3 */ 4 public void dispatchMessage(Message msg) { 5 if (msg.callback != null) { 6 handleCallback(msg); 7 } else { 8 if (mCallback != null) { 9 if (mCallback.handleMessage(msg)) { 10 return; 11 } 12 } 13 handleMessage(msg); 14 } 15 }
机会就是给准备的人,麻痹我终于还是给我找到了。。。。
看方法Line13,这里干嘛了,前边的对于咱们的简单实用的时候尽管放心,没用,因为你没指定callback,所以自然就会走handleMessage方法中来,这个方法熟悉不!!!!!
那个谁》》》》》你说啥不熟悉,奶奶的脚丫子滚蛋,,,,初始化Handler的时候 ,大家重载的那个方法就是这个了。。。
哟,貌似忘记了啥,哦对了,子线程new handler crash问题,,,,,走看看去,报错的位置以及log484这。。。。
1 mLooper = Looper.myLooper(); 2 if (mLooper == null) { 3 throw new RuntimeException( 4 "Can't create handler inside thread that has not called Looper.prepare()"); 5 }
这里是要looper的时候,发现木有,,,,,Why,,,思考下咯,为啥没,那就看看哪里new Looper》???????
查源码发现还是在Looper类中new类。。。
1 /** Initialize the current thread as a looper. 2 * This gives you a chance to create handlers that then reference 3 * this looper, before actually starting the loop. Be sure to call 4 * {@link #loop()} after calling this method, and end it by calling 5 * {@link #quit()}. 6 */ 7 public static final void prepare() { 8 if (sThreadLocal.get() != null) { 9 throw new RuntimeException("Only one Looper may be created per thread"); 10 } 11 sThreadLocal.set(new Looper()); 12 }
额,这就是prepare方法了,也是就是大家禅说的子线程初始化的时候为啥调用这个方法,原因就是这了????
先这样,6666666666