Android中的代理(Proxy)模式

时间:2024-03-05 18:23:50

 

一. 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的子类。