Android采用AIDL实现两个应用间通信

Android采用AIDL实现两个应用间通信

一、前言

作为Android中实现进程间通信的一种方法,AIDL可以很方便的完成这项工作。正如AIDL的名字一样,只需定义一套Client端和Service端交互的接口即可。如需要传递数据的类型为非基本数据类型,需要先将非基本数据类型进行序列化操作。
而在很多实际情况下,Client端与Service端并不在一个应用中,他们作为两个单独的应用存在。为体现这种场景,本文模拟以下例子:Client端应用发送学生姓名及各科成绩至Service应用,由Service端完成学生总成绩的计算工作。

二、代码实现

因涉及到两个App,所以需要创建两个工程。首先实现service端。

1、服务端

创建AIDLService工程,在工程目录下新建IStudent.aidl文件,将在该文件中定义使用的接口:选择File→New→AIDL→AIDL File(或者右键选择New→AIDL→AIDL File),输入IStudent,单击Finish后会自动帮我们创建aidl目录和对应的IStudent.aidl。在这里插入图片描述
修改IStudent.aidl,添加我们需要使用的接口,client端通过调用该接口执行service端的逻辑。虽然aidl文件不是java文件,但package com.example.aidlservice.aidl;这句话一定要写,引入当前的包。

// IStudent.aidl
package com.example.aidlservice.aidl;
...
interface IStudent {
	void addStudentInfoReq(in StudtInfo studtInfo);
}

这里使用了一个自定义StudtInfo类型的对象studtInfo,一定要新建该类型同名aidl。新建StudtInfo.aidl,方法同上。为了说明各文件结构,在aidl的目录下新建一个目录,将StudtInfo.aidl移到该目录下。最终aidl目录如下。
在这里插入图片描述
修改StudtInfo.aidl。如移动了该文件,注意要修改package路径。使用parcelable声明StudtInfo。

// StudtInfo.aidl
package com.example.aidlservice.aidl.student;

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

parcelable StudtInfo;

新建StudtInfo.java,注意一定要在StudtInfo.aidl中package的那个路径下创建。
在这里插入图片描述
实现StudtInfo类。该类型对象需要在进程间传递,所以需要进行序列化操作。继承Parcelable,添加数据的get和set方法。

package com.example.aidlservice.aidl.student;

import android.os.Parcel;
import android.os.Parcelable;

public class StudtInfo implements Parcelable {

    private String name;

    private int mathScore;

    private int englishScore;

    public StudtInfo(String name, int mathScore, int englishScore){
        this.name = name;
        this.mathScore = mathScore;
        this.englishScore = englishScore;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getMathScore() {
        return mathScore;
    }

    public void setMathScore(int mathScore) {
        this.mathScore = mathScore;
    }

    public int getEnglishScore() {
        return englishScore;
    }

    public void setEnglishScore(int englishScore) {
        this.englishScore = englishScore;
    }

    public static Creator<StudtInfo> getCREATOR() {
        return CREATOR;
    }

    private StudtInfo(Parcel in) {
        name = in.readString();
        mathScore = in.readInt();
        englishScore = in.readInt();
    }

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

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

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

    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeString(name);
        parcel.writeInt(mathScore);
        parcel.writeInt(englishScore);
    }
}

新建StudentService类继承自Service,将在该类中完成对Client端请求的逻辑处理。创建一个IStudent.Stub对象,该对象继承自Binder类。实现IStudent.Stub()中的aidl方法,就是实现了之前在IStudent.aidl文件中添加的接口。

private IStudent.Stub stub = new IStudent.Stub() {
    @Override
    public void addStudentInfoReq(StudtInfo studtInfo) {
        Log.d(TAG, "姓名:" + studtInfo.getName()
                + " 数学成绩:" + studtInfo.getMathScore()
                + " 英语成绩:" + studtInfo.getEnglishScore());
    }
};

在onBind中返回这个对象。

public class StudentService extends Service {

    private static final String TAG = "StudentService";

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

修改AndroidManifest.xml。添加该service,并在intent-filter中添加action标签,客户端将通过该标签绑定该服务。

<service android:name=".StudentService"
    android:exported="true">
    <intent-filter>
        <action android:name="com.example.aidlserce.studentservice"/>
    </intent-filter>
</service>

到这里服务端就准备完成了,接着完成客户端。

2、客户端

新建AIDLClient项目,将服务端工程中整个aidl文件夹复制过来,保证目录结构与服务端一致。要确保所有使用的aidl文件都复制过来并且目录一致。同时将继承Parcelable类的StudtInfo.java复制到该工程,也要保证目录与服务端一致。也就是在服务端和客户端都用到的东西一定要两边一模一样各一份,包括aidl文件及自己实现的序列化类。
在这里插入图片描述
修改MainActivity.java,创建一个ServiceConnection对象。在建立连接时调用IStudent.Stub.asInterface(iBinder)将IBinder对象转化为aidl接口。

private IStudent student;
...
private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        student = IStudent.Stub.asInterface(iBinder);
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        unbindService(connection);
    }
};

通过Intent完成远程service的启动。如果你的Android版本高于5.0,选择隐式方式启动远程service的话,需要设置package,需要注意该package为服务端的package。

Intent intent = new Intent();
intent.setAction("com.example.aidlserce.studentservice");
intent.setPackage("com.example.aidlservice");//设置服务端的package
bindService(intent, connection, BIND_AUTO_CREATE);

服务端AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.aidlservice">
    
    ...

</manifest>

将需要传递的数据进行序列化操作,通过上面得到的aidl接口就可以访问服务端的方法了。

StudtInfo studtInfo = new StudtInfo();
studtInfo.setName("小明");
studtInfo.setMathScore(50);
studtInfo.setEnglishScore(30);
try {
    student.addStudentInfoReq(studtInfo);
} catch (RemoteException e) {
    e.printStackTrace();
}

MainActivity源码:

package com.example.aidlclient;

import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import com.example.aidlservice.aidl.IStudent;
import com.example.aidlservice.aidl.student.StudtInfo;

public class MainActivity extends AppCompatActivity {

    private IStudent student;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent = new Intent();
        intent.setAction("com.example.aidlserce.studentservice");
        intent.setPackage("com.example.aidlservice");
        bindService(intent, connection, BIND_AUTO_CREATE);

        Button button1 = findViewById(R.id.button1);
        button1.setOnClickListener(new View.OnClickListener() {
            @SuppressLint("SetTextI18n")
            @Override
            public void onClick(View view) {
                StudtInfo studtInfo = new StudtInfo();
                studtInfo.setName("小明");
                studtInfo.setMathScore(50);
                studtInfo.setEnglishScore(30);
                try {
                    student.addStudentInfoReq(studtInfo);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            student = IStudent.Stub.asInterface(iBinder);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            unbindService(connection);
        }
    };
    
}

整体的流程为:
首先在服务端定义好供客户端调用的方法和自定义类型的aidl,并实现序列化类。创建service,并在service中实现aidl接口。复制aidl文件及序列化类至客户端工程,在客户端中启动远程service,并通过aidl接口访问服务端的方法。
本文中StudtInfo.aidl、IStudent.aidl这两个aidl文件为了说明其中的package和import的关系,所以路径有些复杂,其实完全没有必要建这么多层目录。

项目地址:
客户端
服务端

  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
Android AIDLAndroid Interface Definition Language)是一种Android中用于实现跨进程通信的机制。它允许一个应用程序的进程与另一个应用程序的进程进行交互。 在AIDL中,双向通信可以通过以下步骤实现: 1. 创建AIDL接口:首先,在服务提供方的应用程序中创建一个AIDL接口类,该接口定义了需要在两个应用程序之间进行通信的方法。 2. 实现AIDL接口:在服务提供方的应用程序中实现AIDL接口。这些方法将用于处理由客户端发起的请求。 3. 绑定Service:在客户端应用程序中,通过绑定Service与提供方建立连接。这可以通过Intent和bindService()方法完成。 4. 获取Service接口:一旦客户端与服务提供方建立了连接,客户端将获得Service的接口。这个接口将通过onServiceConnected()方法返回给客户端。 5. 调用方法:客户端可以使用接口对象来调用服务提供方的方法,从而向服务提供方发送请求。 6. 返回结果:服务提供方在接收到请求后,根据请求的类型进行相应的处理,并将处理结果返回给客户端。 通过以上步骤,双向通信将会在两个应用程序之间建立起来。服务提供方可以处理客户端的请求,并将结果返回给客户端。而客户端可以调用服务提供方的方法,并获取所需的数据。 需要注意的是,为了保证AIDL双向通信的正常运行,需要在AndroidManifest.xml文件中声明相应的权限和服务。 总结来说,使用Android AIDL可以实现双向通信。服务提供方与客户端通过AIDL接口进行交互,客户端发送请求给服务提供方,并获取处理结果。这种机制可以方便地实现不同应用程序之间的数据交换和通信。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值