【跨进程】跨进程通信---AIDL

1、AIDL

2、BroadCast

3、Activity

AIDL(Android Interface Defition Language),对外暴露自身接口(该接口只支持方法,不支持常量),用到了Service。上篇关于广播的文章,为了增加难度也使用了Service。

AIDL:

客户端bindService(...)开启服务,unBindService()关闭服务。如果系统自动调用onDestroy()方法,就会自动调用unBindService(),根本原因是Context不存在了。注意:是自动,假如人为调用finish(),会报错,此时需要重写onDestroy(),手动添加unBindService()方法。

服务端实现Service的onBind(Intnt intent)方法,返回一个Binder对象。这个Binder对象是谁?在新建AILD文件的时候,SDK会自动生成一个Stub内部类,它的父类正是Binder,返回Stub即可。

返回Binder对象做什么呢?客户端通过这个Binder对象,得到服务端暴露的接口,进而通过接口方法,获取服务端数据。一段伪代码解释具体过程:

private IMyAidlInterface iMyAidlInterface;//对外暴露的接口
private boolean flag;//跨进程是否成功
private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);//通过Binder对象获得
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            iMyAidlInterface = null;
        }
    };
flag = bindService(intent,serviceConncetion,Context.BIND_AUTO_CREATE);
if(flag){
	iMyAidlInterface.getData();//通过接口方法,跨进程获取数据
} else {
	//跨进程访问失败
}

startService(...)开启服务,stopService()或者stopSelf()关闭服务。startService执行N次,onStart()执行N次,但是只有一个Service对象,所以关闭服务调用一次即可。

实现Service的onBind(Intnt intent)方法,返回一个null。实现onStartCommand(Intent intent,int flags,int startId)具体操作在这里实现,现在官方不建议用onStart()方法了,建议用inStartCommand()提高兼容性。

AIDL效果图:A访问B,获取B的数据。GitHub下载AGitHub下载B

注意:AIDL文件支持哪些数据类型?

基本数据类型、String和CharSequence、List(只支持ArryList)、Map(只支持HashMap)、Pacelable(本文介绍的)、AIDL(接口本身)。


干货AIDL:

准备两个程序:A程序,B程序。

目的:A跨进程访问B,得到数据。(专业一点:B对外暴露接口,A通过接口访问B)

1.创建B程序。

先看一下AIDL文件的结构:



新建AIDL文件IMyAidlInterface.aidl。

package com.wgl.share.share;
import com.wgl.share.share.MyData;//需要手写导入

interface IMyAidlInterface {
    MyData getData();
}

新建类MyData实现Parcelable。

public class MyData implements Parcelable{
    private String data;

    public MyData(String data){
        this.data = data;
    }

    private MyData(Parcel in) {
        data = in.readString();
    }

    public static final Creator<MyData> CREATOR = new Creator<MyData>() {
        @Override
        public MyData createFromParcel(Parcel in) {
            return new MyData(in);
        }

        @Override
        public MyData[] newArray(int size) {
            return new MyData[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(data);
    }

    @Override
    public String toString() {
        return "MyData{" +
                "data='" + data + '\'' +
                '}';
    }
}

新建AIDL文件MyData.aidl(作用,找到自定义类MyData)。只需要两行

package com.wgl.share.share;
parcelable MyData;
新建service类MyService,继承Service
public class MyService extends Service {
    private IMyAidlInterface.Stub iMyAidlInterface = new IMyAidlInterface.Stub() {
        @Override
        public MyData getData() throws RemoteException {
            return new MyData("给你的数据!!!");
        }
    };

    public MyService() {
    }

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

Manifest文件中,注册service:
<application>
<!-- ......  -->
<service
            android:name=".MyService">
            <intent-filter>
                <action android:name="com.wgl.aidl"/>
            </intent-filter>
        </service>

<!-- ......  -->
</application>

在app的build.gradle文件里的<android></android>中间,defaultConfig之后加入(为了找到MyData类)

sourceSets {
        main {
            manifest.srcFile 'src/main/AndroidManifest.xml'
            java.srcDirs = ['src/main/java', 'src/main/aidl']
            resources.srcDirs = ['src/main/java', 'src/main/aidl']
            aidl.srcDirs = ['src/main/aidl']
            res.srcDirs = ['src/main/res']
            assets.srcDirs = ['src/main/assets']
        }
    }
如果还是报错,就sync或者clean一下。

运行A程序

2.创建A程序。

A程序的aidl文件复制过来,别放错位置。

在app的build.gradle文件里的android{},default之后加入:

sourceSets {
        main {
            manifest.srcFile 'src/main/AndroidManifest.xml'
            java.srcDirs = ['src/main/java', 'src/main/aidl']
            resources.srcDirs = ['src/main/java', 'src/main/aidl']
            aidl.srcDirs = ['src/main/aidl']
            res.srcDirs = ['src/main/res']
            assets.srcDirs = ['src/main/assets']
        }
    }
然后在MainActivity里面:
public class MainActivity extends AppCompatActivity {
  private IMyAidlInterface iMyAidlInterface;
    private boolean flag;
    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //跨进程连接B程序
            iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            iMyAidlInterface = null;
        }
    };

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //捆绑Service
        Intent intent = new Intent();
        intent.setAction("com.wgl.aidl");
        intent.setPakage("com.wgl.b");
        flag = mainActivity.bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);
    }

}
最后,在MainActivity里加入一个点击事件,获取B程序数
try {
    //flag = true绑定服务成功
    if(flag){
        MyData a = iMyAidlInterface.getData();
        ToastUtil.getInstance().toastInCenter(mainActivity,a.toString());
 }
  } catch (RemoteException e) {
         e.printStackTrace();}

接下来,给AIDL添加权限验证:

在B程序中,MyService重写onBind方法

 @Override
    public IBinder onBind(Intent intent) {
        String permission = intent.getStringExtra("permission");
        Log.e("MyService:permission",permission);
        int check = checkCallingOrSelfPermission(permission);
        Log.e("MyService:check",check+"");
        if(check == PackageManager.PERMISSION_DENIED) {
            return null;
        }
        return iMyAidlInterface;
    }

同时,在B中Manifests文件里,添加:

<uses-permission android:name="com.wgl.b.permission.ACCESS_B_SERVICE"/>
    
    <permission
        android:name="com.wgl.b.permission.ACCESS_B_SERVICE"
        android:protectionLevel="normal"/>

另一方面,A程序中MainActivity里onCreate方法和doClick方法修改如下:

intent.putExtra("permission","com.wgl.b.permission.ACCESS_B_SERVICE");
if(null != iMyAidlInterface) {
                    MyData data = iMyAidlInterface.getData();
                    Toast.makeText(MainActivity.this,data.toString(),Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(MainActivity.this,"权限验证失败!",Toast.LENGTH_SHORT).show();
                }
其实还有另一种方法,重写Binder的onTransact方法,返回false就是失败,反之成功,不在讲述了。

多提意见和问题。


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的AIDL进程通信示例代码: 定义一个接口: ``` // IMyAidlInterface.aidl interface IMyAidlInterface { int add(int a, int b); } ``` 实现接口: ``` // MyAidlInterfaceImpl.java public class MyAidlInterfaceImpl extends IMyAidlInterface.Stub { @Override public int add(int a, int b) throws RemoteException { return a + b; } } ``` 在服务端绑定接口: ``` // MyService.java public class MyService extends Service { private MyAidlInterfaceImpl myAidlInterfaceImpl; @Override public void onCreate() { super.onCreate(); myAidlInterfaceImpl = new MyAidlInterfaceImpl(); } @Nullable @Override public IBinder onBind(Intent intent) { return myAidlInterfaceImpl; } } ``` 在客户端使用接口: ``` // MainActivity.java public class MainActivity extends AppCompatActivity { private IMyAidlInterface myAidlInterface; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(); intent.setComponent(new ComponentName("com.example.myapp", "com.example.myapp.MyService")); bindService(intent, serviceConnection, BIND_AUTO_CREATE); } private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { myAidlInterface = IMyAidlInterface.Stub.asInterface(iBinder); try { int result = myAidlInterface.add(1, 2); Log.d("MainActivity", "result: " + result); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName componentName) { myAidlInterface = null; } }; } ``` 在客户端中,我们首先创建一个Intent对象,指定服务端应用的包名和服务类名,然后调用bindService()方法连接服务端。连接成功后,我们可以通过asInterface()方法将IBinder对象转换为服务端的接口对象,然后使用接口对象调用服务端的方法。注意,由于进程通信可能会抛出RemoteException异常,因此我们需要在调用接口方法时进行异常处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值