Android开发艺术探索代码尝试----IPC之AIDL篇

Android开发艺术探索的代码尝试----AIDL篇



前言

本次主要记录Android中IPC方式之一,AIDL的使用。本文内容没有涉及AIDL的源码内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、AIDL是什么?

AIDL是**IPC(进程间通信方式)**的一种。
AIDL偏向于底层,它的优点是支持并发,应用面广。但是代码的编写比较繁琐。

二、本次代码的实现目标

在这里插入图片描述

  1. 创建一个Activity作为进程1
  2. 创建一个Service作为进程2
  3. Service中有一个变量mode,作为我们的通信目标。
  4. 所以Activity需要获取和修改 mode(Activity向Service通信)
  5. Service需要通知Activity,mode已被修改。(Service向Activity通信)

三、实现步骤

基本配置

Activity

  1. 默认的Activity模板
  2. 3个Button:绑定服务、获取mode、改变mode

Service

  1. 默认的Service模板
  2. 配置一个mode变量作为通信目标

配置多进程环境

关键词:Android:process字段

在AndroidManiFest文件中修改Activity和Service的配置,添加Android:process字段,process的值表示进程名。

<application
        ...
        <service
            android:name=".Serivice.IPCService"
            android:enabled="true"
            android:exported="true"
            android:process=":secondProcess"/>
            
        <activity 
        	android:name=".MainActivity"
            android:launchMode="singleTask">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        ...
    </application>

编写AIDL文件

一个接口需要对应一个AIDL文件。
故,我们需要两个接口。一个给Activity使用,一个给Service使用。

在编写完AIDL文件后,我们需要点击build,从而生成java文件。本质上我们是使用这个java文件。
AIDL文件的编写规范:

IMyAidlInterface.aidl

// IMyAidlInterface.aidl
package com.example.demo.AIDL;
import com.example.demo.AIDL.IAidlInterface_Listener;
// Declare any non-default types  here with import statements

interface IMyAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void registerListener(IAidlInterface_Listener listener);//注册(获取)监听器
    void changeMode(int mode);//修改mode
    int getMode();//获取mode

IAidlInterface_Listener.aidl

// IAidlInterface_Listener.aidl
package com.example.demo.AIDL;

// Declare any non-default types here with import statements

interface IAidlInterface_Listener {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void onSecondProcessChanged();//通知Activity
}

在Service中实现get和change的AIDL接口

将AIDL接口中的Stub转为Service中的binder,并实现接口方法
Stub是AIDL接口的内部类,继承了IBinder
//IPCService.java
//用于初始化Service的方法,主要初始化了mBinder1,在Activity绑定这个Service时将mBinder返回给Activity
public void init(){
        Mode=0;
        mBinder1 = new IMyAidlInterface.Stub() {
            @Override
            public void registerListener(IAidlInterface_Listener listener) throws RemoteException {
                mListener = listener;//获取Activity传来的listener。
            }

            @Override
            public void changeMode(int mode) throws RemoteException {
                Mode=mode;
                mListener.onSecondProcessChanged();
                Log.d(TAG, "changeMode: mode ="+Mode);
            }

            @Override
            public int getMode() throws RemoteException {
                return Mode;
            }
        };
        mBinder2 = new mBinder();
    }

在Activity中获取AIDL接口的实例并实现Listener的AIDL接口

关键点:使用stub的asInterface()将IBinder转为AIDL接口实例,此时可以调用接口方法。

  1. 绑定Service后获取到Service传来的Binder,利用该Binder获取到AIDL的接口实例(具体如何获取见总结)。
  2. 实现Listener的AIDL接口,实例化Listener,通过Service的接口 传输 这个Listener。

服务绑定

//MainActivity.java
//本地的AIDL接口实例
private IMyAidlInterface iMyAidlInterface=null;
//用于绑定Service使用的ServiceConnection实例
private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);//Binder转换为接口实例
            try {
                mode = iMyAidlInterface.getMode();
                iMyAidlInterface.registerListener(mListener);注册监听器
                Log.d(TAG, "连接服务成功: 注册监听");
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

监听器

private IAidlInterface_Listener mListener = new IAidlInterface_Listener.Stub() {
        @Override
        public void onSecondProcessChanged() throws RemoteException {
            Log.d(TAG, "onSecondProcessChanged: ");//由Service调用
        }
    };

通信测试

Activity
在这里插入图片描述
Log

  1. 点击Bind
    进程1
    在这里插入图片描述
    进程2
    在这里插入图片描述
  2. 获取及修改mode
    在这里插入图片描述

总结

代码尝试到此处,如果对IPC没有深入了解的话,想必会有如下几个疑问:

两个进程间如何传递对象?(本例中传递了监听器)

本质上并没有传递对象,两个进程间的对象不是同一个对象(hashcode不一致)。因为多进程可以看作是两个程序在运行,对于android而言,他会为每一个进程分配虚拟机和内存空间。
那么这个对象是如何传递的?—是依靠序列化和反序列化。
所以这里一个前提,两个进程的代码中需要有一样的aidl包结构,显而易见这是为了序列化和反序列化。

既然进程间传递的对象不是同一个对象,如何保证它能实现需要的功能?(本例中的监听器实例)

这个问题可以转化为----一个实例化的接口对象,在经过序列化和反序列化后还能不能调用重写的接口方法。
答案是,能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值