Android中的代理(Proxy)模式

关山初度尘未洗,策马扬鞭再奋蹄!这篇文章主要讲述Android中的代理(Proxy)模式相关的知识,希望能为你提供帮助。
 
一. Proxy模式定义
Proxy模式,也称代理模式,是经典设计模式中的一种结构型模式,其定义是为其他对象提供一种代理以控制对这个对象的访问,简单的说就是在访问和被访问对象中间加上的一个间接层,以隔离访问者和被访问者的实现细节。
 
二. Proxy模式理解
当无法或者不想直接访问某个对象, 或者访问某个对象存在困难时, 可以通过一个代理对象来间接访问,
为了保证客户端使用的透明性, 委托对象与代理对象需要实现相同的接口。
例如,ActivityManager 作为客户端要访问 AMS,AMS 不希望直接暴露在客户端面前,或者不想被客户端的某些操作影响到自己内部结构,
就暴露出一个代理对象ActivityManagerProxy,让ActivityManagerProxy参与客户端与服务端的交互,这样就完美了。
 
三. Proxy模式应用场景
重点在于AIDL的使用。
 
四. Proxy模式的分类
  1.虚代理( Remote Proxy ):代理一些开销很大的对象,这样便能迅速返回,进行其它操作,只有在真正需要时才实例化;
  2.远程代理( Remote Proxy ): 为一个对象在不同的地址空间提供局部代表。
  3.保护代理(Protection Proxy):控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。
4. 智能指引(Smart Reference): 取代了简单的指针,它在访问对象时执行一些附加操作。

  •   当客户端对象需要访问远程主机中的对象时可以使用远程代理。
  • 当需要用一个消耗资源较少的对象来代表一个消耗资源较多的对象,从而降低系统开销、缩短运行时间时可以使用虚拟代理,例如一个对象需要很长时间才能完成加载时。
  • 当需要为某一个被频繁访问的操作结果提供一个临时存储空间,以供多个客户端共享访问这些结果时可以使用缓冲代理。
  • 通过使用缓冲代理,系统无须在客户端每一次访问时都重新执行操作,只需直接从临时缓冲区获取操作结果即可。
  •   当需要控制对一个对象的访问,为不同用户提供不同级别的访问权限时可以使用保护代理。
  • 当需要为一个对象的访问(引用)提供一些额外的操作时可以使用智能引用代理。
 
五. Proxy模式的优缺点
Android中的代理(Proxy)模式

文章图片

 
六. Proxy模式Demo解析
代理模式类型图:
Android中的代理(Proxy)模式

文章图片

在代理模式中的角色:
● 抽象对象角色:声明了目标对象和代理对象的共同接口,这样一来在任何可以使用目标对象的地方都可以使用代理对象。
● 目标对象角色:定义了代理对象所代表的目标对象。
● 代理对象角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。 代理对象通常在客户端调用传递给目标对象之前或之后,执行某个操作,而不是单纯地将调用传递给目标对象。
 
下面附上代码:
公共接口:
1public interface InterObject { 2public abstract void doEexc(); 3}

 
目标对象角色:

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


代理对象角色:
1 public class ProxyObject new RealObject(); 2@Override 3public void //调用目标对象之前可以做相关操作 4System.out.println("before"); 5realObject.doEexc(); 6//调用目标对象之后可以做相关操作 7System.out.println("after"); 8} 9 }

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

  执行结果:

before 执行操作 after

从上面的例子可以看出代理对象将客户端的调用委派给目标对象,在调用目标对象的方法之前跟之后都可以执行特定的操作。

【Android中的代理(Proxy)模式】 
七. Proxy模式实现过程
以ActivityManager为例,先看一下AMS框架结构图。
 
Android中的代理(Proxy)模式

文章图片

 
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) 2return ActivityManagerNative.getDefault().getServices(maxNum, 0); 3 }

 
继续看看ActivityManagerNative.getDefault()到底干了什么事:实际上是关乎到Singleton< IActivityManager> 类型的gDefault对象创建;
1 private static final Singleton< IActivityManager> gDefault = new 2Singleton< IActivityManager> () { 3protected IActivityManager create() { 4IBinder b = ServiceManager.getService("activity"); 5IActivityManager am = asInterface(b); 6return 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中。
 
Android中的代理(Proxy)模式

文章图片

 
 
下面看一下动态时序图:
Android中的代理(Proxy)模式

文章图片

我们以ActivityManager的getRunningServices()函数为例,对上述序列图进行解析。
1public List< RunningServiceInfo> getRunningServices(int maxNum) 2throws SecurityException { 3try { 4return (List< RunningServiceInfo> )ActivityManagerNative.getDefault() 5.getServices(maxNum, 0); 6} catch (RemoteException e) { 7// System dead, we will be dead too soon! 8return null; 9} 10}

 
可以看到,调用被委托到了ActivatyManagerNative.getDefault()。
1 static public IActivityManager asInterface(IBinder obj){ 2…… 3return new ActivityManagerProxy(obj); 4 }

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

 
从上述简化后的源码可以看到,getDefault()函数返回的是一个ActivityManagerProxy对象的引用,也就是说,ActivityManager得到了一个本地代理。
因为在IActivityManager接口中已经定义了getServices()函数,所以我们来看这个本地代理对该函数的实现。
1public List getServices(int maxNum, int flags) throws RemoteException { 2 3Parcel data = https://www.songbingjia.com/android/Parcel.obtain(); 4Parcel reply = Parcel.obtain(); 5…… 6mRemote.transact(GET_SERVICES_TRANSACTION, data, reply, 0); 7…… 8}

 
从这个代码版段我们看到,调用远端代理的transact()函数,而这个mRemote就是ActivityManagerNative的Binder接口。
接下来我们看一下ActivityManagerNative的代码,因为该类是继承于Binder类的,所以transact的机制此前我们已经展示了代码,对于该类而言,重要的是对onTransact()函数的实现。
1public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 2throws RemoteException { 3 4switch (code) { 5case GET_SERVICES_TRANSACTION: { 6…… 7List list = getServices(maxNum, fl); 8…… 9return true; 10} 11…… 12} 13return super.onTransact(code, data, reply, flags); 14 }

 
在onTrasact()函数内,虽然代码特别多,但就是一个switch语句,根据不同的code命令进行不同的处理,比如对于 GET_SERVICES_TRANSACTION命令,只是调用了getServices()函数。而该函数的实现是在 ActivityManagerService类中,它是ActivityManagerNative的子类。
 

    推荐阅读