设计模式之代理模式

2018-01-22  本文已影响0人  corffen

设计模式之代理模式

1.代理模式的定义

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

2.代理模式的使用场景

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

3.代理模式的UML类图

[图片上传失败...(image-8a4a30-1516557687169)]

4.代理模式的简单实现

`[图片上传失败...(image-7cccf3-1516557687169)]

5.静态代理与动态代理

上面的例子是静态代理,就是说在我们的代码运行前代理类的class编译文件已经存在.</br>
而动态代理与之相反,通过反射机制动态地生成代理者的对象,也就是说在code阶段不会知道代理谁.
具体代理谁会在执行阶段决定.

6.android源码中的代理模式分析

[图片上传失败...(image-b3fd64-1516557687169)]

ActivityManagerProxy就是代理类,ActivityManagerNative是真正的RealSubject类,
而IActivityManger是抽象主题类Subject.
而代理类ActivityManagerProxy的构造函数如下:

`

   public ActivityManagerProxy(IBinder remote)
{
    mRemote = remote;
}

`
事实上ActivityManagerNative是一个抽象类,也就是说真正的主题RealSubject类是它的子类去承担的.这个子类
是ActivityManagerService.

android中管理与维护Activity相关信息的类是一个叫做ActivityManager的类.它的大部分逻辑实际上是由
ActivitymanagerProx承担的.以getAppTasks为例.

在ActivityManger中的

`

  public List<ActivityManager.AppTask> getAppTasks() {
    ArrayList<AppTask> tasks = new ArrayList<AppTask>();
    List<IAppTask> appTasks;
    try {
        appTasks = ActivityManagerNative.getDefault().getAppTasks(mContext.getPackageName());//1.主要逻辑在这
    } 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;
}

`
注意1处,看一下ActivityManagerNative.getDefault()的实现

`

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

`
而gDefault如下:

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

`

在2处,是获取了一个系统级的Service,而这个Service实质上就是ActivityManagerService.
我们来看看ActivityManagerService中getAppTasks()方法.这个是真正干活的地方

`

@Override
public List<IBinder> getAppTasks(String callingPackage) {
    int callingUid = Binder.getCallingUid();
    long ident = Binder.clearCallingIdentity();

    synchronized(this) {
        ArrayList<IBinder> list = new ArrayList<IBinder>();
        try {
            if (DEBUG_ALL) Slog.v(TAG, "getAppTasks");

            final int N = mRecentTasks.size();
            for (int i = 0; i < N; i++) {
                TaskRecord tr = mRecentTasks.get(i);
                // Skip tasks that do not match the caller.  We don't need to verify
                // callingPackage, because we are also limiting to callingUid and know
                // that will limit to the correct security sandbox.
                if (tr.effectiveUid != callingUid) {
                    continue;
                }
                Intent intent = tr.getBaseIntent();
                if (intent == null ||
                        !callingPackage.equals(intent.getComponent().getPackageName())) {
                    continue;
                }
                ActivityManager.RecentTaskInfo taskInfo =
                        createRecentTaskInfoFromTaskRecord(tr);
                AppTaskImpl taskImpl = new AppTaskImpl(taskInfo.persistentId, callingUid);//1
                list.add(taskImpl.asBinder());//2
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
        return list;
    }
}

`
而代理类ActivityManagerProxy中的getAPPTasks()实现如下:

`

    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);//1
    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());//2
            list.add(task);//3
            N--;
        }
    }
    data.recycle();
    reply.recycle();
    return list;
}

`
这里面的逻辑是将数据打包跨进程传递给Server端A(1处)ctivityManagerService处理并返回结果(2,3处).
上面的mRemote则表示服务端的binder.其实就是ActivityManagerService这个类.

总结一下:
`

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

    public IBinder asBinder()
    {
        return mRemote;
    }
    ...
    代码省略
}

`

7.AIDL的简单例子

7.1aidl文件导包的问题

除了基本类型,String,List,Map和CharSequence外,都需要使用import导入相应的类型或者包.

7.2AIDL的流程

1.首先创建一个aidl文件,然后build一下工程,就会在debug包下生成一个同名的java接口类.

`

interface IBankAIDL {

String openAccount(String name,String password);
String saveMoney(int money,String account);
String takeMoney(int money,String account,String password);
String closeAccount(String account,String password);

}
`

build一下之后会生成如下的文件
[图片上传失败...(image-7a413e-1516557687169)]

2.上述接口类中含有xxxAIDL.Stub,创建一个Binder类继承自这个类

实现如下:
`

public class BankBinder extends IBankAIDL.Stub {
@Override
public String openAccount(String name, String password) throws RemoteException {
    return name +"开户成功!账号为: "+ UUID.randomUUID().toString();
}

@Override
public String saveMoney(int money, String account) throws RemoteException {
    return null;
}

@Override
public String takeMoney(int money, String account, String password) throws RemoteException {
    return null;
}

@Override
public String closeAccount(String account, String password) throws RemoteException {
    return null;
}

}
`
注意到继承的类是生成的IBankAIDLjava类的内部类Stub,然后实现的是声明的接口中的四个方法

3.创建一个Service,比如BinderService击沉桃子Service,然后在onBind()方法中,返回2中的Binder类.

`

public class BankService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
    return new BankBinder();
}

}

`

4.在Activity中bindService,在ServiceConnection中返回我们生命的IBankAIDL接口,其实就是2中的Binder.

`

//private BankBinder mBankBinder;//服务端的binder对象
private IBankAIDL mBankBinder;//服务端的binder对象


private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        //mBankBinder = (BankBinder) service;
        mBankBinder = IBankAIDL.Stub.asInterface(service);//1
        
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {

    }
};

`
1处代码其实是生成了一个Proxy.把代理赋值给IBankAIDL.我们来看看Proxy的实现,如下代码:

`

private static class Proxy implements com.corffen.jnidemo.IBankAIDL
{
    private android.os.IBinder mRemote;
    Proxy(android.os.IBinder remote)
    {
    mRemote = remote;
    }

    @Override public android.os.IBinder asBinder()
    {
    return mRemote;
    }
    public java.lang.String getInterfaceDescriptor()
    {
    return DESCRIPTOR;
    }
    ....
    接口中的方法实现省略
}

`
很明显Proxy的构造方法中持有了一个IBinder的引用,而我们真正干活的BankBinder类是继承自Binder类的.

5.在Activity中就可以调用IBankAIDL(这是我们生命的接口,aidl文件生成的)中的方法了.
调用接口中的方法,也就是调用代理类Proxy中的方法,由代理模式可知,调用proxy中的方法其实就是调用
真正干活RealSubject中的方法,也就是BankBinder中的方法.这个类是服务端提供的.

分析一下:如果我们的Server代码在另一个进程中,我们的Client端,(Activity)如何调用Server中的代码?
首先二者都需要有一个共同的IBinder接口,也就是有相同的aidl文件,IDE会为我们生成stub.
然后在service的onBind()中返回继承自Stub类的Binder.
注意上述的binder类中包含了提供接口中的方法的实现
最后在Client端,就是Activity中绑定Server,然后返回一个IBinder实例,调用binder中的方法,即可..

[图片上传失败...(image-676f7c-1516557687169)]

对于Client端来说,也就是Activity,只需要bindService,来初始化我们的IBankAIDL这个接口
然后调用这个接口中的方法,就可以实现调用Service端真正干活的方法.这样就实现了跨进程通信.
他的实现原理是使用binder机制.
其实在client端的ServiceConnection中初始化的IBankAIDL这个接口,是得到的是这个接口中的proxy.
而这个proxy在构造的时候传入了一个IBinder接口.
而服务端的BankBinder类是继承自Stub类的,而它是继承自Binder类的.
也就是说这样,Activity中调用接口的方法,就是调用proxy中的方法,而根据代理模式知道
调用proxy方法,就是调用RealSubject中的方法,也就是服务端BankBinder中的方法,真正干活的类.

上一篇下一篇

猜你喜欢

热点阅读