关闭

Android设计模式源码解析之Proxy模式

标签: 设计模式源码代理androidbinder
14949人阅读 评论(25) 收藏 举报
分类:

Android设计模式源码解析之Proxy模式

本文为 Android 设计模式源码解析 中 Proxy模式 分析
Android系统版本: 5.0
分析者:singwhatiwanna,分析状态:完成,校对者:Mr.Simple,校对状态:已校对

Binder中的代理模式

在说Binder中的代理模式之前,我们需要先看看代理模式的简单实现,这一部分内容采用了《JAVA与模式》之代理模式这篇文章中的代码示例和uml类图。

1. 模式介绍

代理模式是对象的结构模式。代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。

模式的使用场景

就是一个人或者机构代表另一个人或者机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

2. UML类图

url

角色介绍

  • 抽象对象角色:声明了目标对象和代理对象的共同接口,这样一来在任何可以使用目标对象的地方都可以使用代理对象。

  • 目标对象角色:定义了代理对象所代表的目标对象。

  • 代理对象角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或之后,执行某个操作,而不是单纯地将调用传递给目标对象。

3. 模式的简单实现

简单实现的介绍

下面通过一种抽象的方式来实现下代理模式

实现源码

抽象对象角色

public abstract class AbstractObject {
    //操作
    public abstract void operation();
}

目标对象角色

public class RealObject extends AbstractObject {
    @Override
    public void operation() {
        //一些操作
        System.out.println("一些操作");
    }
}

代理对象角色

public class ProxyObject extends AbstractObject{
    RealObject realObject = new RealObject();
    @Override
    public void operation() {
        //调用目标对象之前可以做相关操作
        System.out.println("before");        
        realObject.operation();        
        //调用目标对象之后可以做相关操作
        System.out.println("after");
    }
}

客户端

public class Client {
    public static void main(String[] args) {
        AbstractObject obj = new ProxyObject();
        obj.operation();
    }
}

4. 代理模式在Binder中的使用

直观来说,Binder是Android中的一个类,它继承了IBinder接口。从IPC角度来说,Binder是Android中的一种跨进程通信方式,Binder还可以理解为一种虚拟的物理设备,它的设备驱动是/dev/binder,该通信方式在linux中没有;从Android Framework角度来说,Binder是ServiceManager连接各种Manager(ActivityManager、WindowManager,etc)和相应ManagerService的桥梁;从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当你bindService的时候,服务端会返回一个包含了服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务。

Binder一个很重要的作用是:将客户端的请求参数通过Parcel包装后传到远程服务端,远程服务端解析数据并执行对应的操作,同时客户端线程挂起,当服务端方法执行完毕后,再将返回结果写入到另外一个Parcel中并将其通过Binder传回到客户端,客户端接收到返回数据的Parcel后,Binder会解析数据包中的内容并将原始结果返回给客户端,至此,整个Binder的工作过程就完成了。由此可见,Binder更像一个数据通道,Parcel对象就在这个通道中跨进程传输,至于双方如何通信,这并不负责,只需要双方按照约定好的规范去打包和解包数据即可。

为了更好地说明Binder,这里我们先手动实现了一个Binder。为了使得逻辑更清晰,这里简化一下,我们来模拟一个银行系统,这个银行提供的功能只有一个:即查询余额,只有传递一个int的id过来,银行就会将你的余额设置为id*10,满足下大家的发财梦。

  1. 先定义一个Binder接口
package com.ryg.design.manualbinder;

import android.os.IBinder;
import android.os.IInterface;
import android.os.RemoteException;

public interface IBank extends IInterface {

    static final String DESCRIPTOR = "com.ryg.design.manualbinder.IBank";

    static final int TRANSACTION_queryMoney = (IBinder.FIRST_CALL_TRANSACTION + 0);

    public long queryMoney(int uid) throws RemoteException;

}

2.创建一个Binder并实现这个上述接口

package com.ryg.design.manualbinder;

import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;

public class BankImpl extends Binder implements IBank {

    public BankImpl() {
        this.attachInterface(this, DESCRIPTOR);
    }

    public static IBank asInterface(IBinder obj) {
        if ((obj == null)) {
            return null;
        }
        android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
        if (((iin != null) && (iin instanceof IBank))) {
            return ((IBank) iin);
        }
        return new BankImpl.Proxy(obj);
    }

    @Override
    public IBinder asBinder() {
        return this;
    }

    @Override
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
        switch (code) {
        case INTERFACE_TRANSACTION: {
            reply.writeString(DESCRIPTOR);
            return true;
        }
        case TRANSACTION_queryMoney: {
            data.enforceInterface(DESCRIPTOR);
            int uid = data.readInt();
            long result = this.queryMoney(uid);
            reply.writeNoException();
            reply.writeLong(result);
            return true;
        }
        }
        return super.onTransact(code, data, reply, flags);
    }

    @Override
    public long queryMoney(int uid) throws RemoteException {
        return uid * 10l;
    }

    private static class Proxy implements IBank {
        private IBinder mRemote;

        Proxy(IBinder remote) {
            mRemote = remote;
        }

        @Override
        public IBinder asBinder() {
            return mRemote;
        }

        public java.lang.String getInterfaceDescriptor() {
            return DESCRIPTOR;
        }

        @Override
        public long queryMoney(int uid) throws RemoteException {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            long result;
            try {
                data.writeInterfaceToken(DESCRIPTOR);
                data.writeInt(uid);
                mRemote.transact(TRANSACTION_queryMoney, data, reply, 0);
                reply.readException();
                result = reply.readLong();
            } finally {
                reply.recycle();
                data.recycle();
            }
            return result;
        }

    }

}

ok,到此为止,我们的Binder就完成了,这里只要创建服务端和客户端,二者就能通过我们的Binder来通信了。这里就不做这个示例了,我们的目的是分析代理模式在Binder中的使用。

我们看上述Binder的实现中,有一个叫做“Proxy”的类,它的构造方法如下:

  Proxy(IBinder remote) {
      mRemote = remote;
  }

Proxy类接收一个IBinder参数,这个参数实际上就是服务端Service中的onBind方法返回的Binder对象在客户端重新打包后的结果,因为客户端无法直接通过这个打包的Binder和服务端通信,因此客户端必须借助Proxy类来和服务端通信,这里Proxy的作用就是代理的作用,客户端所有的请求全部通过Proxy来代理,具体工作流程为:Proxy接收到客户端的请求后,会将客户端的请求参数打包到Parcel对象中,然后将Parcel对象通过它内部持有的Ibinder对象传送到服务端,服务端接收数据、执行方法后返回结果给客户端的Proxy,Proxy解析数据后返回给客户端的真正调用者。很显然,上述所分析的就是典型的代理模式。至于Binder如何传输数据,这涉及到很底层的知识,这个很难搞懂,但是数据传输的核心思想是共享内存。

5. 杂谈

优点与缺点

优点

  • 给对象增加了本地化的扩展性,增加了存取操作控制

缺点

  • 会产生多余的代理类

Android技术交流群

  • 29969245
18
5
查看评论

Android设计模式之代理模式 Proxy

一.概述 代理模式也是平时比较常用的设计模式之一,代理模式其实就是提供了一个新的对象,实现了对真实对象的操作,或成为真实对象的替身.在日常生活中也是很常见的.例如A要租房,为了省麻烦A会去找中介,中介会替代A去筛选房子,A坐享中介筛选的结果,并且交房租也是交给中介,这就是一个典型的日...
  • l2show
  • l2show
  • 2015-07-28 22:14
  • 20608

Android开发中的代理模式

上一篇文章Android开发中单例模式写法与可能遇到的坑讲到了单例模式的一般写法,本篇继续总结一下Android(Java)中比较常用的代理模式。和单例模式一样,代理模式也是经常使用到的,使用过Spring的小伙伴,应该比较清楚,其AOP代理就默认使用JDK自带动态代理来生成代理类的。在Androi...
  • chenkai19920410
  • chenkai19920410
  • 2017-01-22 15:10
  • 1274

Android设计模式(四)--代理模式

1、定义: 为其他对象提供一种代理以控制对这个对象的访问。 2、使用: 在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。 3、作用: 代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了的作用和保护了目标对象的作用。 4、划分: 代...
  • naibbian
  • naibbian
  • 2015-06-04 09:22
  • 818

Android中的代理模式

代理的概念:为某个对象提供一个代理,以控制对这个对象的访问。 代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。 抽象对象角色:就是代理类和委托类共同的接口,声明了目标...
  • hp910315
  • hp910315
  • 2016-04-09 18:54
  • 990

Android开发中无处不在的设计模式——动态代理模式

继续更新设计模式系列,写这个模式的主要原因是最近看到了动态代理的代码。 先来回顾一下前5个模式: - Android开发中无处不在的设计模式——单例模式 - Android开发中无处不在的设计模式——Builder模式 - Android开发中无处不在的设计模式——观察者模式 - ...
  • sbsujjbcy
  • sbsujjbcy
  • 2016-01-21 11:37
  • 7573

Android设计模式源码解析之Proxy模式

Android设计模式源码解析之Proxy模式 本文为 Android 设计模式源码解析 中 Proxy模式 分析 Android系统版本: 5.0 分析者:singwhatiwanna,分析状态:完成,校对者:Mr.Simple,校对状态:已校对 Binder中的代理模...
  • singwhatiwanna
  • singwhatiwanna
  • 2015-03-24 12:58
  • 14949

代理模式与Android

代理模式(Proxy)一、   什么是代理模式先来看看官方的说法,代理模式就是为其他对象提供一种代理,以控制对这个对象的访问。 看来这个官方的说法的确有点官方,看了还是让人感觉不点不知所措,还是不明白代理模式是什么,究竟是用来做什么的。 其实代理这个...
  • ljianhui
  • ljianhui
  • 2014-06-09 00:25
  • 8158

Java设计模式-代理模式之动态代理(附源码分析)

Java设计模式-代理模式之动态代理(附源码分析) 动态代理概念及类图 上一篇中介绍了静态代理,动态代理跟静态代理一个最大的区别就是:动态代理是在运行时刻动态的创建出代理类及其对象。上篇中的静态代理是在编译的时候就确定了代理类具体类型,如果有多个类需要代理,那么就得创建多个。还...
  • yujin753
  • yujin753
  • 2015-06-26 17:37
  • 2255

设计模式(结构型)之代理模式(Proxy Pattern)

代理模式是常用的结构型设计模式之一,当无法直接访问某个对象或访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,所访问的真实对象与代理对象需要实现相同的接口。根据代理模式的使用目的不同,代理模式又可以分为多种类型,例如保护代理、远程代理、虚拟代理、缓冲代理等,它们应用于...
  • yanbober
  • yanbober
  • 2015-05-04 18:48
  • 5687

代理模式在android中使用

  • 2015-04-29 17:44
  • 1.65MB
  • 下载
    我的书
    微信公众号
    公众号
    聚焦于『Android开发前沿、AI技术、职业发展、生活感悟、妹子图』,欢迎大家关注。
    一句话介绍自己
    Android 资深工程师、混过腾讯、百度和滴滴,《Android开发艺术探索》作者
    爱生活,爱技术,爱妹子,爱游戏
    1群:215680213(已满)
    2群:190283084(已满)
    8群:635778578

    我的联系方式
    QQ:289832127
    singwhatiwanna@gmail.com

    知识星球 - 欢迎铁粉加入
    公众号
    个人资料
    • 访问:1966106次
    • 积分:16346
    • 等级:
    • 排名:第754名
    • 原创:89篇
    • 转载:2篇
    • 译文:0篇
    • 评论:3091条
    博客专栏
    我的微博
    最新评论