編輯:關於Android編程
相信大家對於Android中的Handler是在為熟悉不過了,但是要知道,Handler就其本身而言只是一個殼子,真正在內部起到作用的是Message這個類,對於Message這個類,相信大家也不會陌生,正如大家經常用到的Message.obtain()的方法一樣。但是大家又是否知道obtain()方法裡面為我們做了哪些操作了,下面我就帶領大家進行Message的王國,去一探究竟吧。
首先映入眼簾的是這樣的一行代碼:
public final class Message implements Parcelable
下面我們需要關注的四個成員變量分別是:
1)public int what
2)public int arg1
3)public int arg2
4)public Object obj
我們經常是用到這樣的幾個參數,但是其真實的含義是否真正的理解呢?只要google的內部的注釋才是真正的可靠的。
1)用戶定義消息的識別碼,以便於系統識別出當前的消息是關於什麼的。由於每一個Handle對於自己的消息的識別碼都有自己的命名空間。所以我們也就不用擔心各個不同的Handler之間會存在沖突的情況。
2)其中第二個參數與第三個參數的意義是一樣的,注釋上是這樣說明的,這兩個參數,如果用戶只是需要傳輸簡單的int類型的數據,相比較於setData(Bundle bundle),代價更低。
3)第四個參數,按照注釋上的說明,是這樣理解的:這是一個發送給接受者的一個隨意的數據,如果使用Messager來進行發送數據進行跨進程的通信,那麼當前的obj如果實現了Parcelable就一定不能夠為空指針,對於其他的數據的傳輸,我們一般使用setData方法就可以了。但是需要注意的是,對於高於android.os.Build.VERSION_CODES#FROYO的版本,這裡的Parcelable對象是不支持的。
上面的變量講完了以後,接下來,我們還需要講解另外的一組常量的定義:
private static final Object sPoolSync = new Object(); private static Message sPool; private static int sPoolSize = 0; //池塘裡最大的尺寸 private static final int MAX_POOL_SIZE = 50;
1、第一個變量其實就是充當鎖的作用,避免多線程爭搶資源,導致髒數據
2、sPool這個變量可以理解為消息隊列的頭部的指針
3、sPoolSize是當前的消息隊列的長度
4、定義消息隊列緩存消息的最大的長度。
Ok,到這裡,Message的成員變量已經講解完畢,接下來主要是講解其中的Api方法。
第一個方法就是大家經常用到的obtain方法,而且不帶任何的參數:
public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; sPoolSize--; return m; } } return new CustomMessage(); }www.2cto.com首先為了避免多線程進行爭搶資源,給sPoolSync進行加鎖。首先判斷當前的隊列的指針是否為空,如果當前的指針已經不為空,當前的隊列的頭部的消息就是可以重用並且被取出,那麼當前的隊列的頭指針指向當前的消息的下一個消息,也就是m.next,同時把取出的消息的尾部指針置為null,隊列的長度減1.
第二個方法:
public static Message obtain(Message orig) { Message m = obtain(); m.what = orig.what; m.arg1 = orig.arg1; m.arg2 = orig.arg2; m.obj = orig.obj; m.replyTo = orig.replyTo; if (orig.data != null) { m.data = new Bundle(orig.data); } m.target = orig.target; m.callback = orig.callback; return m; }我們可以看到,這個方法相對於上面的方法多了一個orig的參數,從上面的代碼我們可以看到,首先從隊列中取出Message的對象,然後對其中的參數的對象的各個數據進行逐一的拷貝,並最終返回對象。
第三個方法如下:
public static Message obtain(Handler h) { Message m = obtain(); m.target = h; return m; }不用多說,這個函數中為當前創建的消息指定了一個Handler對象,因為我們知道Handler是Message的最終的目的地。
public static Message obtain(Handler h, Runnable callback) { Message m = obtain(); m.target = h; m.callback = callback; return m; }相對於上面的方法,這裡面多了一行m.callback = callback,按照注釋上面的說明,當一些消息真正的被執行的時候,callback這個Runnbale方法將會被觸發執行的。
接下來有一系列的方法的邏輯是差不多的,我們取其中的一個進行講解:
public static Message obtain(Handler h, int what, int arg1, int arg2) { Message m = obtain(); m.target = h; m.what = what; m.arg1 = arg1; m.arg2 = arg2; return m; }也就是說創建一個Message的時候,順便可以為這個Message提供一些邏輯上需要的參數。
消息有創建,那麼就必然存在回收的概念,下面我們一起來看一下:
public void recycle() { clearForRecycle(); synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } }
void clearForRecycle() { flags = 0; what = 0; arg1 = 0; arg2 = 0; obj = null; replyTo = null; when = 0; target = null; callback = null; data = null; }
在clearForRecycle這個函數中,是做一些回收的預處理的操作,該置為0的參數置為0,該置為null的參數置為null。在recycle的函數中,只要當前的緩存的隊列的長度沒有超過上限,將當前的消息添加到隊列的尾部。
下面的方法是關於實現Parcelable所需要的方法:
public static final Parcelable.CreatorCREATOR = new Parcelable.Creator () { public Message createFromParcel(Parcel source) { Message msg = Message.obtain(); msg.readFromParcel(source); return msg; } public Message[] newArray(int size) { return new Message[size]; } }; public int describeContents() { return 0; } public void writeToParcel(Parcel dest, int flags) { if (callback != null) { throw new RuntimeException( "Can't marshal callbacks across processes."); } dest.writeInt(what); dest.writeInt(arg1); dest.writeInt(arg2); if (obj != null) { try { Parcelable p = (Parcelable)obj; dest.writeInt(1); dest.writeParcelable(p, flags); } catch (ClassCastException e) { throw new RuntimeException( "Can't marshal non-Parcelable objects across processes."); } } else { dest.writeInt(0); } dest.writeLong(when); dest.writeBundle(data); Messenger.writeMessengerOrNullToParcel(replyTo, dest); } private void readFromParcel(Parcel source) { what = source.readInt(); arg1 = source.readInt(); arg2 = source.readInt(); if (source.readInt() != 0) { obj = source.readParcelable(getClass().getClassLoader()); } when = source.readLong(); data = source.readBundle(); replyTo = Messenger.readMessengerOrNullFromParcel(source); }
Ok,Message的內核源碼的剖析就講解到這裡,相信大家以後再用到這個類的時候會有更深的理解啦。
今年春節晚會沒看盡興,被支付寶集福給添了一段插曲,朋友們都在那數定時間段不停的咻一咻,哇,我咻到一個敬業福,不可能的,哈哈。那麼咻一咻功能基於程序代碼是怎麼實現的呢?下面
前面寫過了使用ViewFlipper和ViewPager實現屏幕中視圖切換的效果(ViewPager未實現輪播)附鏈接:ANDROID中使用VIEWFLIPPER類實現屏
一、問題描述 為提高圖片加載的效率,需要對圖片的采用緩存和異步加載策略,編碼相對比較復雜,實際上有一些優秀的框架提供了解決方案,比如近期在git上比較活躍的xut
本文實例為大家分享了Android控件ImageSwitcher實現引導界面的代碼,供大家參考,具體內容如下效果圖:布局代碼:<?xml version=1