Android中的代理(Proxy)模式
Posted 浪里小白龙
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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模式的优缺点
六. 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)模式的主要内容,如果未能解决你的问题,请参考以下文章
阿里四面:你知道Spring AOP创建Proxy的过程吗?