当前位置: 首页 > article >正文

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

目录

5、 谁来写Proxy及Stub类呢?

如何考虑人的分工

IA接口知识取得的难题

在编程上,有什么技术可以实现这个方法?

范例


5、 谁来写Proxy及Stub类呢?

       -- 强龙提供AIDL工具,给地头蛇产出Proxy和Stub类

如何考虑人的分工
  • 由框架开发者来撰写Proxy-Stub类,才能减轻开发者的负担。
  • 框架分为: <天子框架>和<曹操框架>。
  • 因此, 应该由两者(天子或曹操)之一来撰写Proxy-Stub类。
     
IA接口知识取得的难题
  • 但是,有个难题: IA接口(如下图所示)的内容必须等到<买主>来了才会知道。
  • 在框架开发阶段,买主还没来, IA接口的知识无法取得,又如何定义IA接口呢? 没有IA接口定义,又如何撰写Stub和Proxy类呢?

 

  • 好办法是:

“强龙(天子或曹操)撰写代码(在先) ;然后地头蛇(App开发者)定义接口(在后)。 ”

在编程上,有什么技术可以实现这个方法?

技术之一是: 類別模板(class template)例如,强龙撰写模板:
 

template< class T >
class SomeClass
{
    private:
            T data;
    public:
        SomeClass() { }
        void set(T da)
        { data = da; }
};
  • 地头蛇利用模板来生成一个类:

        SomeClass<Integer> x;

由于接口(interface)是一种特殊的类(class),所以也可以定义模板如下:

 

template<interface I>
    class BinderProxy
    {
        // ………
    };
  • 地头蛇利用模板来生成一个类:
  • 除了模板之外,还有其它编程技术可以实现<强龙写代码,地头蛇定义接口>的方案吗?
  • 答案是:
       程序生成器(program generator)
       例如: Android的aidl.exe

AIDL

  • AIDL的目的是定义Proxy/Stub来封装IBinder接口,以便产生更亲切贴心的新接口。
  • •所以,在应用程序里,可以选择使用IBinder接口,也可以使用AIDL来定义出接口。
  • AIDL的目的是定义Proxy/Stub来封装IBinder接口,以便产生更亲切贴心的新接口。
  • 所以,在应用程序里,可以选择使用IBinder接口,也可以使用AIDL来定义出新接口。由于IBinder接口只提供单一函数(即transact()函数)来进行远距通信,呼叫起来比较不方便。
  • 所以Android提供aidl.exe工具来协助产出Proxy和Stub类别,以化解这个困难。
  • 只要你善于使用开发环境的工具(如Android的aidl.exe软件工具)自动产生Proxy和Stub类别的程序代码;那就很方便
    了。
     
范例
  • 此范例使用Android-SDK的/tools/里的aidl.exe工具程序,根据接口定义档(如下述的mp3PlayerInterface.aidl)而自动产出Proxy及Stub类别,其结构如下:

 

  • 藉由开发工具自动产出Proxy及Stub类的代码,再分别转交给ac01和mp3Binder开发者。此范例程序执行时,出现画面如下:
  • 依据UI画面的两项功能: <Play>和< Stop>,以Java定义接口,如下的代码:
// mp3PlayerInterface.aidl
interface mp3PlayerInterface mp3PlayerInterface{
    void play();
    void stop();
}
  • 使用Android-SDK所含的aidl.exe工具,将上述的mp3PlayerInterface.aidl档翻译成为下述的mp3PlayerInterface.java档案。
// mp3PlayerInterface.java
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: mp3PlayerInterface.aidl
*/
// ………
public interface mp3PlayerInterface extends android.os.IInterface
{
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements com.misoo.pkgx.mp3PlayerInterface
    {
        // ……….
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
        {
            switch (code){
                case INTERFACE_TRANSACTION:{
                    reply.writeString(DESCRIPTOR);
                    return true;
                }

                case TRANSACTION_play:{
                    data.enforceInterface(DESCRIPTOR);
                    this.play();
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_stop:{
                    data.enforceInterface(DESCRIPTOR);
                    this.stop();
                    reply.writeNoException();
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.misoo.pkgx.mp3PlayerInterface
        {
            private android.os.IBinder mRemote;
            //………….
            public void play() throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        mRemote.transact(Stub.TRANSACTION_play, _data, _reply, 0);
                        _reply.readException();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                } 
            }
        }

        public void stop() throws android.os.RemoteException
        {
            android.os.Parcel _data = android.os.Parcel.obtain();
            android.os.Parcel _reply = android.os.Parcel.obtain();
            try {
                _data.writeInterfaceToken(DESCRIPTOR);
                mRemote.transact(Stub.TRANSACTION_stop, _data, _reply, 0);
                _reply.readException();
            }
            finally {
                _reply.recycle();
                _data.recycle();
            }
        }

        static final int TRANSACTION_play = (IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_stop = (IBinder.FIRST_CALL_TRANSACTION + 1);
    }
    public void play() throws android.os.RemoteException;
    public void stop() throws android.os.RemoteException;
}
  • 表面上,此mp3PlayerInterface.java是蛮复杂的,其实它的结构是清晰又简单的,只要对于类继承、反向調用和接口等面向对象观念有足够的认识,就很容易理解了。
// mp3Binder.java
package com.misoo.pkgx;
import android.content.Context;
import android.media.MediaPlayer;
import android.util.Log;

public class mp3Binder extends mp3PlayerInterface.Stub{
    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; }
    }
}
  • 撰写mp3RemoteService类
     
// mp3Service.java
package com.misoo.pkgx;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class mp3Service extends Service {
    IBinder ib = null;
    @Override public void onCreate() {
        super.onCreate();
        ib = new mp3Binder(this.getApplicationContext());
    }

    @Override public void onDestroy() { }
    @Override public IBinder onBind(Intent intent) {return ib;}
}

// 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 = mp3PlayerInterface.Stub.asInterface(ibinder);
        }
        public void onServiceDisconnected(ComponentName className) {}
    };

    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;
        }
    }
}
  • 对于Anrdoid的初学者而言, Android的        AIDL机制可说是最难弄懂的。

http://www.kler.cn/a/500822.html

相关文章:

  • 里氏替换原则(Liskov Substitution Principle,LSP):面向对象设计的基本原则
  • 亚远景-ASPICE评估:汽车软件项目的过程能力评价
  • excel VBA 基础教程
  • 工业 4G 路由器赋能远程医疗,守护生命线
  • [石榴翻译] 维吾尔语音识别 + TTS语音合成
  • 计算机网络之---子网划分与IP地址
  • GPT大模型下,如何实现网络自主防御
  • Python对接GitHub:详细操作指南
  • Docker与微服务实战2-基础篇
  • 【人工智能语音识别】——深入详解人工智能语音信号处理:理解语音信号的特征提取与表示
  • hive3后创建表默认是外部表问题
  • Spring整合SpringMVC
  • 电商项目-基于ElasticSearch实现商品搜索功能(四)
  • Kotlin 协程基础三 —— 结构化并发(二)
  • 国产3D CAD将逐步取代国外软件
  • Excel中身份证号码都变成E+乱码显示如何处理?
  • 2024 Java若依(RuoYi)框架视频教程(课件+示例代码+视频)
  • 【DevOps】Jenkins使用Pipline发布Web项目
  • WEB前端-3.1
  • 抖音矩阵是什么
  • 探索 Cloudflare Workers:高效边缘计算的新选择
  • 浅谈云计算02 | 云计算模式的演进
  • Flutter中Get.snackbar避免重复显示的实现
  • Gitlab-Runner配置
  • ModbusTCP转CCLINKIE在机器人中的革命性应用!
  • ConvNeXt V2: Co-designing and Scaling ConvNets with Masked Autoencoders论文解读