Bootstrap

深入Android架构(从线程到AIDL)_21 IPC的Proxy-Stub设计模式03

目录

3、包裝IBinder接口  -- 使用Proxy-Stub设计模式

EIT造型的双层组合 

4、 谁来写Proxy及Stub类呢?     -- 地头蛇(App开发者)自己写

范例

定义一个新接口: IPlayer

 撰写一个Stub类: PlayerStub

撰写mp3Binder类

撰写mp3RemoteService类


3、包裝IBinder接口  -- 使用Proxy-Stub设计模式

  • 采用Proxy-Stub设计模式将IBinder接口包装起来,让App与IBinder接口不再产生高度相依性。
  • 其将IBinder接口包装起来,转换出更好用的新接口:
  • Proxy类提供较好用的IA接口给Client使用。
  • Stub类别则是屏蔽了Binder基类的onTransact()函数,然后将IA接口里的f1()和f2()函数定义为抽象函数。于是简化了App开发的负担:
EIT造型的双层组合 

4、 谁来写Proxy及Stub类呢?     -- 地头蛇(App开发者)自己写

范例
  • 兹写一个App范例, 程序执行时出现画面如下:

  • 在这个范例里,定义了一个IPlayer接口,然后规划了PlayerProxy和PlayerStub两的类,如下图:
定义一个新接口: IPlayer
// IPlayer.java
package com.misoo.pkgx;
public interface IPlayer {
    void play();
    void stop();
    String getStatus();
}
 撰写一个Stub类: PlayerStub
// PlayerStub.java
package com.misoo.pkgx;
import android.os.Binder;
import android.os.Parcel;
public abstract class PlayerStub extends Binder implements IPlayer{
    @Override 
    public boolean onTransact(int code, Parcel data,Parcel reply, int flags) throws android.os.RemoteException {
        reply.writeString(data.readString()+ " mp3");
        if(code == 1) this.play();
        else if(code == 2) this.stop();
        return true;
    }

    public abstract void play();
    public abstract void stop();
    public abstract String getStatus();
}

撰写一个Proxy类: PlayerProxy

// PlayProxy.java
private class PlayerProxy implements IPlayer{
    private IBinder ib;
    private String mStatus;
    PlayerProxy(IBinder ibinder)
         { ib = ibinder; }

    public void play(){
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeString("playing");
        try { ib.transact(1, data, reply, 0);
            mStatus = reply.readString();
        } catch (Exception e) { e.printStackTrace(); }
    }

    public void stop(){
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeString("stop");
        try { ib.transact(2, data, reply, 0);
            mStatus = reply.readString();
        } catch (Exception e) { e.printStackTrace(); }
    }

    public String getStatus() { return mStatus; }
}

APP的代码

撰写mp3Binder类
 
// mp3Binder.java
// ……..
public class mp3Binder extends PlayerStub{
    private MediaPlayer mPlayer = null;
    private Context ctx;
    public mp3Binder(Context cx){ ctx= cx; }

    public void play(){
        if(mPlayer != null) return;
        mPlayer = MediaPlayer.create(ctx, R.raw.test_cbr);
        try { mPlayer.start();
        } catch (Exception e) {
            Log.e("StartPlay", "error: " + e.getMessage(), e); }}

    public void stop(){
        if (mPlayer != null)
            { mPlayer.stop(); mPlayer.release(); mPlayer = null; }
    }

    public String getStatus() { return null; }
}
撰写mp3RemoteService类
 
// mp3RemoteService.java
package com.misoo.pkgx;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class mp3RemoteService extends Service {
    private IBinder mBinder = null;
    @Override public void onCreate() {
        mBinder = new mp3Binder(getApplicationContext());
    }

    @Override
    public IBinder onBind(Intent intent) { return mBinder; }
}

// ac01.java
// ………
public class ac01 extends Activity implements OnClickListener {
    //……….
    private PlayerProxy pProxy = null;
    public void onCreate(Bundle icicle) {
        // ………
        startService(new Intent("com.misoo.pkgx.REMOTE_SERVICE"));
        bindService(new Intent("com.misoo.pkgx.REMOTE_SERVICE"),
        mConnection, Context.BIND_AUTO_CREATE); }
        private ServiceConnection mConnection = new ServiceConnection() {
            public void onServiceConnected(ComponentName className,IBinder ibinder)
                { pProxy = new PlayerProxy(ibinder); }
            public void onServiceDisconnected(ComponentName classNa){}
        };

    public void onClick(View v) {
        switch (v.getId()) {
            case 101: pProxy.play(); tv.setText(pProxy.getStatus());
                break;
            case 102: pProxy.stop(); tv.setText(pProxy.getStatus());
                break;
            case 103:
                unbindService(mConnection);
                stopService(new Intent("com.misoo.pkgx.REMOTE_SERVICE"));
                finish(); break;
        }
    }
}
  • PlayerStub类将onTransact()函数隐藏起来,提供一个更具有美感、更亲切的新接口给mp3Binder类使用。
  • 隐藏了onTransact()函数之后,mp3Binder类的开发者就不必费心去了解onTransact()函数了。于是, PlayerProxy与PlayerStub两个类遥遥相对,并且将IPC细节知识(例如transact()和onTransact()函数之参数等)包夹起来。

 

 

;