Android技术知识Android开发Android开发经验谈

Android源码设计模式(六)— 编程好帮手:代理模式

2018-07-12  本文已影响150人  随时学丫

Android源码设计模式(一) -- 面向对象的六大原则
Android源码设计模式(二)-- 应用最广的模式:单例模式
Android源码设计模式(三)-- 自由扩展你的项目:Builder 模式
Android源码设计模式(四)-- 时势造英雄:策略模式
Android源码设计模式(五)-- 使编程更有灵活性:责任链模式
Android源码设计模式(六)— 编程好帮手:代理模式
Android源码设计模式(七)— 解决、解耦的钥匙 — 观察者模式

简书 MD 语法不识别 [TOC] ,也不会根据标题行(#) 来插入目录,作为每次看资料喜欢先看目录把握总体的我来说,很不习惯,查找跳转也不方便,所以,如果看到文章没有目录预览的,请安装脚本:简书目录脚本地址

一、代理模式的定义

对其他对象提供一种代理以控制对这个对象的访问。

二、代理模式的使用场景

当无法或不想直接访问某个对象或访问某个对象存在困难时,可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口。

三、代理模式的 UML 类图】

代理模式 UML

角色介绍

四、代理模式的简单实现

借助一个生活中案例来理解代理模式。小民以前在公司上班时,就遇到被老板拖欠工资甚至克扣工资的情况,这种情况下小民还是通过法律途径来解决问题,一旦小民选择了走法律途径,那么不可避免地要请律师作为自己的诉讼代理人,我们将诉讼流程抽象在一个接口类中。

public interface ILawsuit {
    //提交申请
    void submit();
    //进行举证
    void burden();
    //开始辩护
    void defend();
    //诉讼完成
    void finish();
}

具体诉讼人:小民

该类实现 ILawsuit 的 4 个方法做出具体的实现逻辑,虽然逻辑很简单,只是输出了一句话。当然,小民不可以自己去打官司,于是小民请了个律师代理自己进行诉讼。

public class XiaoMin implements ILawsuit {
    @Override
    public void submit() {
        //老板欠小民工资,小民只好申请仲裁
        System.out.println("老板拖欠工资,特此申请仲裁!");
    }
    @Override
    public void burden() {
        //小民证据充足,不怕告不赢
        System.out.println("这是合同书和过去一年的银行工资流水!");
    }
    @Override
    public void defend() {
        //铁证如山,辩证也没什么好说的
        System.out.println("证据确凿!不需要再说什么了!");
    }
    @Override
    public void finish() {
        //结果也是肯定的,必赢
        System.out.println("诉讼成功,判决老板即日起七天内结算工资!");
    }
}

诉讼代理人:律师

在该类中会持有一个呗代理者的引用,律师所执行的方法实质就是简单的调用被代理者中的方法。

public class Lawyer implements ILawsuit {
    ILawsuit lawsuit;//持有一个具体被代理的引用
    public Lawyer(ILawsuit lawsuit) {
        this.lawsuit = lawsuit;
    }
    @Override
    public void submit() {
        lawsuit.submit();
    }
    @Override
    public void burden() {
        lawsuit.burden();
    }
    @Override
    public void defend() {
        lawsuit.defend();
    }
    @Override
    public void finish() {
        lawsuit.finish();
    }
}

客户类

public class Client {
    public static void main(String[] args) {
        ILawsuit xiaoMin = new XiaoMin();
        ILawsuit lawyer = new Lawyer(xiaoMin);
        lawyer.submit();
        lawyer.burden();
        lawyer.burden();
        lawyer.finish();
    }
}
//---------------------------------运行结果--------------------------------------------------
老板拖欠工资,特此申请仲裁!
这是合同书和过去一年的银行工资流水!
这是合同书和过去一年的银行工资流水!
诉讼成功,判决老板即日起七天内结算工资!

代理模式其实就是一种委托模式,真实对象将方法的执行委托给代理对象,其实大家还可以发散思维。

正如一个代理类可以代理多个被代理类,即:一个律师可以代理很多个人打官司。

被代理类也可以有多个代理类,即:小民还可以找不同的律师打官司。

而我们只需要定义不同的代理类和被代理类实现 ILawsuit 接口即可。

正如文开头所述,代理模式是一个非常重要的模式,所以本文会讲得多一些,希望读者耐心细读。代理模式大致可以分为两部分。

而 Java 给我们提供了一个便捷的动态代理接口 InvocationHandler,实现该接口需要重写其调用方法 invoke。

package java.lang.reflect;
public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

在这里,我们主要通过 invoke 方法来调用具体的被代理方法,也就是真实的方法。动态代理可以使得我们的代码逻辑更加简洁,不过在此之前我们首先完善动态代理类。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class DynamicProxy implements InvocationHandler {
    private Object obj;

    public DynamicProxy(Object obj) {
        this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
         //proxy:代表被代理的类
         //method:表示代理类中的方法
        Object result = method.invoke(obj, args);
        return result;
    }

}

如上代码,我们声明一个 Object 的引用,该引用指向被代理者,而我们调用被代理者的具体方法则在 invoke 方法中,也就是说我们原来由代理类做的工作现在都由 谁我们 InvocationHandler 来完成,不需要关心到底代理谁。

public class Client {
    public static void main(String[] args) {
        //构造小民
        ILawsuit xiaoMin = new XiaoMin();
        //构造动态代理
        DynamicProxy proxy = new DynamicProxy(xiaoMin);
        //获取被代理小民的 ClassLoader
        ClassLoader classLoader = xiaoMin.getClass().getClassLoader();
        //动态构造一个代理律师
        ILawsuit lawyer = (ILawsuit) Proxy.newProxyInstance(classLoader, new Class[] { ILawsuit.class }, proxy);
        //律师诉讼
        lawyer.submit();
        //律师举证
        lawyer.burden();
        //律师辩护
        lawyer.burden();
        //完成诉讼
        lawyer.finish();
    }
}
//---------------------------------运行结果--------------------------------------------------
老板拖欠工资,特此申请仲裁!
这是合同书和过去一年的银行工资流水!
这是合同书和过去一年的银行工资流水!
诉讼成功,判决老板即日起七天内结算工资!

由此可见动态代理通过一个代理类来代理 N 多个被代理类,其实质是对代理者与被代理者进行解耦,使两者没有直接的耦合关系。

相对于静态代理则只为给定接口下的实现做代理,而接口不同那么久需要重新定义不同的代理类,较为复杂,但是静态代理更符合面向对象原则。在开始时具体使用哪种代理,根据情况。

静态代理和动态代理是从 code 方面来区分代理模式的两种方式,我们也可以通过试用范围来区分不同的代理实现。

五、Android 中代理模式实现

Android 源码中不少关于代理模式的实现,比如源码中的 ActivityManagerProxy 代理类,其具体代理的是 ActivityManagerNative 的子类 ActivityManagerService,我们主要看看 ActivityManagerProxy 这个类,该类与 ActivityManagerNative 这个类处于同一文件。

class ActivityManagerProxy implements IActivityManager {
    public ActivityManagerProxy(IBinder remote) {
        mRemote = remote;
    }

    public IBinder asBinder() {
        return mRemote;
    }

    public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeString(callingPackage);
        intent.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeStrongBinder(resultTo);
        data.writeString(resultWho);
        data.writeInt(requestCode);
        data.writeInt(startFlags);
        if (profilerInfo != null) {
            data.writeInt(1);
            profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
        } else {
            data.writeInt(0);
        }
        if (options != null) {
            data.writeInt(1);
            options.writeToParcel(data, 0);
        } else {
            data.writeInt(0);
        }
        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
        reply.readException();
        int result = reply.readInt();
        reply.recycle();
        data.recycle();
        return result;
    }
    //.............实现了 IActivityManager 中的抽象方法
}

ActivityManagerProxy 实现了 IActivityManager 中的抽象方法,该接口定义了 Activity 相关的接口方法,其中有些是我们常接触到的。

public interface IActivityManager extends IInterface {
    public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
            String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags,
                ProfilerInfo profilerInfo, Bundle options) throws RemoteException;
    
    public ComponentName startService(IApplicationThread caller, Intent service,
                String resolvedType, String callingPackage, int userId) throws RemoteException;
    
    public int stopService(IApplicationThread caller, Intent service,
                String resolvedType, int userId) throws RemoteException;
    
    public int bindService(IApplicationThread caller, IBinder token, Intent service,
                String resolvedType, IServiceConnection connection, int flags,
                String callingPackage, int userId) throws RemoteException;
    
    public boolean unbindService(IServiceConnection connection) throws RemoteException;
    
    public Intent registerReceiver(IApplicationThread caller, String callerPackage,
                IIntentReceiver receiver, IntentFilter filter,
                String requiredPermission, int userId) throws RemoteException;
    
    public void unregisterReceiver(IIntentReceiver receiver) throws RemoteException;
    
    public int checkPermission(String permission, int pid, int uid)
                throws RemoteException;
    //........
}

上面的 IActivityManager 就相当于代理模式中的抽象主题,那么真实的主题是谁呢?就是上面我们提到过的继承于 ActivityManagerNative 的 ActivityManagerService 类。


AMS.png

通过 UML 图可以清晰的看到 ActivityManagerProxy 和 ActivityManagerNative 都实现了 IActivityManager,严格来说,ActivityManagerProxy 就是代理部分,而真实部分实质上是 ActivityManagerService,因为 ActivityManagerNative 是个抽象类,大多数逻辑都在 ActivityManagerService 中。

ActivityManagerService 是系统级的 Service 并运行于自己所处的进程空间中,可以通过 ServiceManager 来获取它。而 ActivityManagerProxy 也运行在自己的进程空间,两者并不相同,显然 ActivityManagerProxy 和 ActivityManagerService 通信是通过跨进程通信,上述类中也可以看到,这里跨进程的实现是基于 Android 中的Binder 机制,而上述的代理类型为 远程代理。

ActivityManagerProxy 在实际的逻辑处理中并未过多地被外部类使用,因为在 Android 管理与维护 Activity 相关的类是另外一个叫做 ActivityManager 的类,ActivityManager 虽说管理 Activity 信息,但实质上其大多数逻辑都是 ActivityManagerProxy 承担。这里以 ActivityManager 中的 getAppTasks 方法为例。

public List<ActivityManager.AppTask> getAppTasks() {
    ArrayList<AppTask> tasks = new ArrayList<AppTask>();
    List<IAppTask> appTasks;
    try {
        appTasks = ActivityManagerNative.getDefault().getAppTasks(mContext.getPackageName());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
    int numAppTasks = appTasks.size();
    for (int i = 0; i < numAppTasks; i++) {
        tasks.add(new AppTask(appTasks.get(i)));
    }
    return tasks;
}

逻辑就是简单的调用 ActivityManagerNative 的 getDefault() 方法获取 IActivityManager 类型对象,然后通过这个对象调用其 getAppTasks() 方法。

static public IActivityManager getDefault() {
    return gDefault.get();
}

private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            if (false) {
                Log.v("ActivityManager", "default service binder = " + b);
            }
            IActivityManager am = asInterface(b);
            if (false) {
                Log.v("ActivityManager", "default service = " + am);
            }
            return am;
        }
};

上述代码构造了一个 Singleton<IActivityManager> 的 gDefault 对象,其中通过ServiceManager.getService("activity") 获取了系统级 Service。Service 实质上就是 ActivityManagerService,这里也就创建了一个对 ActivityManagerService 的 Client 代理对象 ActivityManagerProxy 的实例,ActivityManagerProxy 中的 getAppTasks 方法逻辑就很明确,将数据打包跨进程传递给 Server 端的 ActivityManagerService 处理并返回结果。

public List<IAppTask> getAppTasks(String callingPackage) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeString(callingPackage);
        mRemote.transact(GET_APP_TASKS_TRANSACTION, data, reply, 0);
        reply.readException();
        ArrayList<IAppTask> list = null;
        int N = reply.readInt();
        if (N >= 0) {
            list = new ArrayList<>();
            while (N > 0) {
                IAppTask task = IAppTask.Stub.asInterface(reply.readStrongBinder());
                list.add(task);
                N--;
            }
        }
        data.recycle();
        reply.recycle();
        return list;
}

主要是通过 Binder 机制获取信息,通过 mRemote.transact() 方法获取 Client 端的数据,然后 AIDL 获取到 IAppTask 实例,将数据添加到集合中,并通过 reply 发送出去。

Android 中的 Binder 机制

想要仔细学习 Binder 机制的,推荐一篇博客,讲述了跨进程的一系列,是迄今为止,我看到解析最详细最易懂的 Binder 解析,讲完了跨进程通信的来龙去脉。

Android跨进程通信:图文详解 Binder机制 原理

六、总结

优点

缺点

上一篇 下一篇

猜你喜欢

热点阅读