1. 程式人生 > >Android中的代理(Proxy)模式

Android中的代理(Proxy)模式

ner try 都是 switch語句 困難 .cn turn 重新 交互

一. Proxy模式定義

Proxy模式,也稱代理模式,是經典設計模式中的一種結構型模式,其定義是為其他對象提供一種代理以控制對這個對象的訪問,簡單的說就是在訪問和被訪問對象中間加上的一個間接層,以隔離訪問者和被訪問者的實現細節。

二. Proxy模式理解

當無法或者不想直接訪問某個對象, 或者訪問某個對象存在困難時, 可以通過一個代理對象來間接訪問,

為了保證客戶端使用的透明性, 委托對象與代理對象需要實現相同的接口。

例如,ActivityManager 作為客戶端要訪問 AMS,AMS 不希望直接暴露在客戶端面前,或者不想被客戶端的某些操作影響到自己內部結構,

就暴露出一個代理對象ActivityManagerProxy,讓ActivityManagerProxy參與客戶端與服務端的交互,這樣就完美了。

三. Proxy模式應用場景

重點在於AIDL的使用。

四. Proxy模式的分類

1.虛代理( Remote Proxy ):代理一些開銷很大的對象,這樣便能迅速返回,進行其它操作,只有在真正需要時才實例化;

2.遠程代理( Remote Proxy ): 為一個對象在不同的地址空間提供局部代表。

3.保護代理(Protection Proxy):控制對原始對象的訪問。保護代理用於對象應該有不同的訪問權限的時候。

4. 智能指引(Smart Reference): 取代了簡單的指針,它在訪問對象時執行一些附加操作。

  • 當客戶端對象需要訪問遠程主機中的對象時可以使用遠程代理。
  • 當需要用一個消耗資源較少的對象來代表一個消耗資源較多的對象,從而降低系統開銷、縮短運行時間時可以使用虛擬代理,例如一個對象需要很長時間才能完成加載時。
  • 當需要為某一個被頻繁訪問的操作結果提供一個臨時存儲空間,以供多個客戶端共享訪問這些結果時可以使用緩沖代理。
  • 通過使用緩沖代理,系統無須在客戶端每一次訪問時都重新執行操作,只需直接從臨時緩沖區獲取操作結果即可。
  • 當需要控制對一個對象的訪問,為不同用戶提供不同級別的訪問權限時可以使用保護代理。
  • 當需要為一個對象的訪問(引用)提供一些額外的操作時可以使用智能引用代理。

五. Proxy模式的優缺點

技術分享

六. Proxy模式Demo解析

代理模式類型圖:

技術分享

在代理模式中的角色:

  ● 抽象對象角色:聲明了目標對象和代理對象的共同接口,這樣一來在任何可以使用目標對象的地方都可以使用代理對象。

  ● 目標對象角色:定義了代理對象所代表的目標對象。

  ● 代理對象角色:代理對象內部含有目標對象的引用,從而可以在任何時候操作目標對象;代理對象提供一個與目標對象相同的接口,以便可以在任何時候替代目標對象。 代理對象通常在客戶端調用傳遞給目標對象之前或之後,執行某個操作,而不是單純地將調用傳遞給目標對象。

下面附上代碼:

公共接口:

1  public interface InterObject {
2       public abstract void doEexc(); 
3  } 

目標對象角色:



1 public class RealObject implements InterObject {
2         @Override
3         public void //執行的操作
4                System.out.println("執行操作");
5         }
6 }

代理對象角色:

1 public class ProxyObject new RealObject();
2         @Override
3         public void //調用目標對象之前可以做相關操作
4             System.out.println("before");        
5             realObject.doEexc();        
6             //調用目標對象之後可以做相關操作
7             System.out.println("after");
8         }
9 }

Client:

1 public class Client {
2         public static void main(String[] args) {
3             // TODO Auto-generated method stub
4             RealObject rel = new RealObject();
5             InterObject obj = new ProxyObject();
6             obj.doEexc(); 
7         }
8 } 

執行結果:

before
執行操作
after
從上面的例子可以看出代理對象將客戶端的調用委派給目標對象,在調用目標對象的方法之前跟之後都可以執行特定的操作

七. Proxy模式實現過程

以ActivityManager為例,先看一下AMS框架結構圖。

技術分享

1. IActivityManager作為ActivityManagerProxy和ActivityManagerNative的公共接口,所以兩個類具有部分相同的接口,可以實現合理的代理模式;

2. ActivityManagerProxy代理類是ActivityManagerNative的內部類;

3. ActivityManagerNative是個抽象類,真正發揮作用的是它的子類ActivityManagerService(系統Service組件)。

4. ActivityManager是一個客戶端,為了隔離它與,有效降低甚至消除二者的耦合度,在這中間使用了ActivityManagerProxy代理類,所有對的訪問都轉換成對代理類的訪問,這樣ActivityManager就與解耦了,這是典型的proxy的應用場景。

5. ActivityManagerService是系統統一的Service,運行在獨立的進程中;通過系統ServiceManger獲取;ActivityManager運行在一個進程裏面,ActivityManagerService運行在另一個進程內,對象在不同的進程裏面,其地址是相互獨立的;采用Binder機制跨進程通信,所以我們可以得出這是一個RemoteProxy。

這裏涉及到兩個過程:

  代理對象建立:ActivityManagerProxy代理對象的創建;

  程序執行過程:如何通過代理對象來執行真正對象請求;

 下面看看這兩個過程。

1. 代理對象建立

是在ActivityManager的getRunningServices執行時就需要代理類來執行;

1 public List<RunningServiceInfo> getRunningServices(int maxNum)
2   return ActivityManagerNative.getDefault().getServices(maxNum, 0);
3 }

  繼續看看ActivityManagerNative.getDefault()到底幹了什麽事:實際上是關乎到Singleton<IActivityManager>類型的gDefault對象創建;

1 private static final Singleton<IActivityManager> gDefault = new
2        Singleton<IActivityManager>() {
3       protected IActivityManager create() {
4       IBinder b = ServiceManager.getService("activity");
5       IActivityManager am = asInterface(b);
6       return am;
7   }
8 };

  ServiceManager.getService("activity");獲取系統的“activity”的Service, 所有的Service都是註冊到ServiceManager進行統一管理。

  這樣就創建了一個對ActivityManagerService實例的本地代理對象ActivityManagerProxy實例。Singleton是通用的單例模板類。

ActivityManagerNative.getDefault就返回一個此代理對象的公共接口IActivityManager類型,就可以在本地調用遠程對象的操作方法

2. 程序執行過程

仍以getRunningServices方法為例,ActivityManager執行getRunningServices,創建ActivityManagerProxy實例

其實實際執行的是ActivityManagerNative的代碼,但是ActivityManagerNative是個抽象類,所以真正有效的代碼在 ActivityManagerNative 的子類 ActivityManagerService中。

技術分享

下面看一下動態時序圖:

技術分享

我們以ActivityManager的getRunningServices()函數為例,對上述序列圖進行解析。

 1  public List<RunningServiceInfo> getRunningServices(int maxNum)
 2             throws SecurityException {
 3         try {
 4             return (List<RunningServiceInfo>)ActivityManagerNative.getDefault()
 5                     .getServices(maxNum, 0);
 6         } catch (RemoteException e) {
 7             // System dead, we will be dead too soon!
 8             return null;
 9         }
10     }

可以看到,調用被委托到了ActivatyManagerNative.getDefault()。

 1 static public IActivityManager asInterface(IBinder obj){
 2          ……
 3         return new ActivityManagerProxy(obj);
 4 }


7 static public IActivityManager getDefault(){ 8 …… 9 IBinder b = ServiceManager.getService("activity"); 10 gDefault = asInterface(b); 11 return gDefault; 12 }

從上述簡化後的源碼可以看到,getDefault()函數返回的是一個ActivityManagerProxy對象的引用,也就是說,ActivityManager得到了一個本地代理。

因為在IActivityManager接口中已經定義了getServices()函數,所以我們來看這個本地代理對該函數的實現。

1  public List getServices(int maxNum, int flags) throws RemoteException {
2 
3         Parcel data = Parcel.obtain();
4         Parcel reply = Parcel.obtain();
5                    ……
6          mRemote.transact(GET_SERVICES_TRANSACTION, data, reply, 0);
7         ……
8  }

從這個代碼版段我們看到,調用遠端代理的transact()函數,而這個mRemote就是ActivityManagerNative的Binder接口。

接下來我們看一下ActivityManagerNative的代碼,因為該類是繼承於Binder類的,所以transact的機制此前我們已經展示了代碼,對於該類而言,重要的是對onTransact()函數的實現。

 1  public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
 2             throws RemoteException {
 3 
 4         switch (code) {
 5         case GET_SERVICES_TRANSACTION: {
 6              ……
 7             List list = getServices(maxNum, fl);
 8              ……
 9             return true;
10         }
11         ……
12         }
13        return super.onTransact(code, data, reply, flags);
14 }    

在onTrasact()函數內,雖然代碼特別多,但就是一個switch語句,根據不同的code命令進行不同的處理,比如對於 GET_SERVICES_TRANSACTION命令,只是調用了getServices()函數。而該函數的實現是在 ActivityManagerService類中,它是ActivityManagerNative的子類。

Android中的代理(Proxy)模式