編輯:關於Android編程
前言:
(1)在android中線程間的消息通信是通過handler實現的。handler的常見應用:因為在android中對UI操作只能在主線程中操作,而一些耗時的操作又不能在主線程進行,所以會在子線程做一些網絡請求等的耗時操作,然後通過handler把子線程的任務切換到主線程中,在主線程中進行UI操作。如下代碼:
private Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new Thread(new Runnable() { @Override public void run() { Message message = Message.obtain(); message.what = 1; handler.sendMessage(message); } }).start(); }
(2)handler的運行其實需要looper和messageQueue支持,只是當新建Activity已經幫我們新建了looper和messageQueue。如果在子線程使用handler,必須調用Looper.prepare和Looper.loop。如下代碼:
class MyThread implements Runnable{ private Handler handler; @Override public void run() { Looper.prepare(); handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; Looper.loop(); } }
(3)handler的應用流程。首先通過Looper.prepare(),將Looper綁定到當前線程,創建Looper實例時會創建一個MessageQueue。當新建一個Handler實例時會獲取到當前的線程的Looper和MessageQUeue。當通過handler.sendMessage(message)方法時會把Message插入到MessageQueue中。最後通過Looper.loop()不停遍歷MessageQueue,得到Message,並交給msg.target處理,target就是當前handler(handle賦值給msg.target是在handler.sendMessage(message)中實現的)。target會調用msg.target.dispatchMessage(msg)處理,dispatchMessage最後會調用 handleMessage(msg)處理message。handleMessage也是我們需要重寫的方法。下面將下各方法的實現原理。
1.Looper.prepare()
Looper.prepare()的作用是創建一個Looper並綁定到當前線程,同時創建一個MessageQueue。Looper綁定到當前線程通過ThreadLocal實現的。
ThreadLocal的作用:為不同線程互不干擾的存儲和提供數據(具體原理可以看下singwhatiwanna大神的這篇文章點擊打開鏈接)。
在代碼的78行sThreadLocal.set(new Looper(quitAllowed)),新建了一個Looper實例存儲到了ThreadLocal中,並在這之前判定了ThreadLocal之前是否存儲了Looper,不為null則拋出異常,這樣保證了一個線程只有一個Looper。
51 52 public final class More ...Looper { 53 private static final String TAG = "Looper"; 54 55 // sThreadLocal.get() will return null unless you've called prepare(). 56 static final ThreadLocalsThreadLocal = new ThreadLocal (); 57 private static Looper sMainLooper; // guarded by Looper.class 58 59 final MessageQueue mQueue; 60 final Thread mThread; 61 62 private Printer mLogging;
70 public static void More ...prepare() { 71 prepare(true); 72 } 73
74 private static void More ...prepare(boolean quitAllowed) { 75 if (sThreadLocal.get() != null) { 76 throw new RuntimeException("Only one Looper may be created per thread"); 77 } 78 sThreadLocal.set(new Looper(quitAllowed)); 79 }
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mRun = true; mThread = Thread.currentThread(); }
Handler的構造方法的第198行mLooper = Looper.myLooper()獲取了當前線程的Looper。再看下Looper.myLooper()的實現,其實是獲取了LocalThread存儲的Looper, return sThreadLocal.get()第161行,就是在代碼78行保存的Looper。
mQueue = mLooper.mQueue(203行)獲取了MessageQueu。這樣通過新建一個Handler對象,通過ThreadLocal使Handler和Looper,MessageQueue聯系到一起。
187 188 public More ...Handler(Callback callback, boolean async) { 189 if (FIND_POTENTIAL_LEAKS) { 190 final Class klass = getClass(); 191 if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && 192 (klass.getModifiers() & Modifier.STATIC) == 0) { 193 Log.w(TAG, "The following Handler class should be static or leaks might occur: " + 194 klass.getCanonicalName()); 195 } 196 } 197 198 mLooper = Looper.myLooper(); 199 if (mLooper == null) { 200 throw new RuntimeException( 201 "Can't create handler inside thread that has not called Looper.prepare()"); 202 } 203 mQueue = mLooper.mQueue; 204 mCallback = callback; 205 mAsynchronous = async; 206 }
160 public static Looper More ...myLooper() { 161 return sThreadLocal.get(); 162 }
505 public final boolean More ...sendMessage(Message msg) 506 { 507 return sendMessageDelayed(msg, 0); 508 }
516 517 public final boolean More ...sendEmptyMessage(int what) 518 { 519 return sendEmptyMessageDelayed(what, 0); 520 }
531 public final boolean More ...sendEmptyMessageDelayed(int what, long delayMillis) { 532 Message msg = Message.obtain(); 533 msg.what = what; 534 return sendMessageDelayed(msg, delayMillis); 535 }
592 public boolean More ...sendMessageAtTime(Message msg, long uptimeMillis) { 593 MessageQueue queue = mQueue; 594 if (queue == null) { 595 RuntimeException e = new RuntimeException( 596 this + " sendMessageAtTime() called with no mQueue"); 597 Log.w("Looper", e.getMessage(), e); 598 return false; 599 } 600 return enqueueMessage(queue, msg, uptimeMillis); 601 }
626 private boolean More ...enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { 627 msg.target = this; 628 if (mAsynchronous) { 629 msg.setAsynchronous(true); 630 } 631 return queue.enqueueMessage(msg, uptimeMillis); 632 }
4.Looper.loop().
當MessageQueue有消息時,會遍歷MessageQueue,獲取到Message,然後交給Handler處理。MessageQueue沒有消息時則處於阻塞狀態。
public static void More ...loop() { 110 final Looper me = myLooper(); 111 if (me == null) { 112 throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); 113 } 114 final MessageQueue queue = me.mQueue; 115 116 // Make sure the identity of this thread is that of the local process, 117 // and keep track of what that identity token actually is. 118 Binder.clearCallingIdentity(); 119 final long ident = Binder.clearCallingIdentity(); 120 121 for (;;) { 122 Message msg = queue.next(); // might block 123 if (msg == null) { 124 // No message indicates that the message queue is quitting. 125 return; 126 } 127 128 // This must be in a local variable, in case a UI event sets the logger 129 Printer logging = me.mLogging; 130 if (logging != null) { 131 logging.println(">>>>> Dispatching to " + msg.target + " " + 132 msg.callback + ": " + msg.what); 133 } 134 135 msg.target.dispatchMessage(msg); 136 137 if (logging != null) { 138 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); 139 } 140 141 // Make sure that during the course of dispatching the 142 // identity of the thread wasn't corrupted. 143 final long newIdent = Binder.clearCallingIdentity(); 144 if (ident != newIdent) { 145 Log.wtf(TAG, "Thread identity changed from 0x" 146 + Long.toHexString(ident) + " to 0x" 147 + Long.toHexString(newIdent) + " while dispatching to " 148 + msg.target.getClass().getName() + " " 149 + msg.callback + " what=" + msg.what); 150 } 151 152 msg.recycleUnchecked(); 153 } 154 }
代碼121到153無限便利MessageQueue.
代碼122行(Message msg = queue.next();)獲取到了Message,如果沒有則處於阻塞狀態。
代碼135行(msg.target.dispatchMessage(msg);)msg交給了msg.target處理,target就是在新建Handler實例時賦值給它的當前Handler。這裡把msg交給了handler.dispatchMessage(msg)處理,我們看下dispatchMessage的代碼。
93 public void More ...dispatchMessage(Message msg) { 94 if (msg.callback != null) { 95 handleCallback(msg); 96 } else { 97 if (mCallback != null) { 98 if (mCallback.handleMessage(msg)) { 99 return; 100 } 101 } 102 handleMessage(msg); 103 } 104 }
在dispatchMessage方法中如果msg.callback和mCallback為null則交給102行(handleMessage(msg);)處理,handlerMessage就是我們需要重寫,去處理返回的消息。
如果msg.callback不為null,看下95行handleCallback(msg),該方法實現739行(message.callback.run()),其實callback就是一個Runnable。我們在handler.post(runnable)設置了callback。
private static void More ...handleCallback(Message message) { 739 message.callback.run(); 740 } 741
324 public final boolean More ...post(Runnable r) 325 { 326 return sendMessageDelayed(getPostMessage(r), 0); 327 }
725 private static Message More ...getPostMessage(Runnable r) { 726 Message m = Message.obtain(); 727 m.callback = r; 728 return m; 729 } 730
進入官網(http://opencv.org/)下載OpenCV for android並解壓,不知道什麼原因,嘗試過幾次下載的很慢,時常斷開,後來有一次突然就很順利的下
自學了android有幾個月了,跟著網上的節奏,應該早點寫些博客來提高自己的水准的。但苦於技術水准始終不自信(也是不過關的結果吧),就一直只是將自己學習過程中的問題和重要
場景隨著移動支付的興起,在我們的app中,會經常有集成支付的需求.這時候一般都會采用微信和支付寶的sdk 來集成(一)支付寶支付在使用支付寶支付的過程中,我們是在服務器端
前言在 Android 5.0 之前,我們已經有了 overridePendingTransition() 方法來實現一些轉場效果。然而,在 Android 5.0 以後