Android AIDL 简单的2个例子 标准数据类型和自定义数据类型

本文介绍了使用AIDL的两种方式,一是传递标准数据类型,需在服务端创建AIDL文件和service并暴露接口,客户端拷贝AIDL文件并绑定service;二是传递自定义数据类型,服务端要添加数据类型AIDL、定义自定义类型等,客户端拷贝相关文件并绑定service。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文将介绍如何去使用AIDL,这里有2种,一种是传递标准数据类型,另一种是传递自定义数据类型。

第一种:

这里分2个项目,一个是AIDL服务端,一个是AIDL客户端。

服务端:

1.创建AIDL文件

右击你的项目,选择new->AIDL->AIDL File

然后你就能看到代码结构中多了一个AIDL文件

打开AIDL文件,你会看到这里已经有一个接口了,不用管,这个是系统自动生成的,只是告诉你可以使用哪些数据类型的。然后我们只需要添加一个我们自己的接口。

// IRemoteService.aidl
package com.example.myaidl;

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

interface IRemoteService {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

    //添加一个接口

    int getId();
}

 

2.创建service,把接口暴露给客户端

新建一个service,在AndroidMainfest中添加一个action,为了其他apk可以绑定这个service。

        <service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.myaidl.service.action" />
            </intent-filter>
        </service>

在service中实现刚才的AIDL接口

package com.example.myaidl;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

public class MyService extends Service {
    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return binder;
    }

    private final IRemoteService.Stub binder = new IRemoteService.Stub() {
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }

        //实现了刚才我们定义的接口,这里就是一个简单的例子,比较简单。
        @Override
        public int getId() throws RemoteException {
            return 100;
        }
    };

}

服务端的功能已经完成了,下面看如何在客户端(别的程序)如何来使用服务端(这个程序)的接口。

客户端:

1.拷贝AIDL文件

新建一个项目,直接把服务端那个AIDL文件夹拷贝到你的项目中。

2.绑定service

客户端去绑定服务端的service,客户端的onServiceConnected()回调函数将会收到一个binder,这个binder就是服务端service那里onBind()返回的,其实就是AIDL接口。

代码比较简单,点击按钮就去调用一次接口。

package com.example.myaidlclient;

import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
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.util.Log;
import android.view.View;
import android.widget.Button;

import com.example.myaidl.IRemoteService;


public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private IRemoteService iRemoteService;

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

        Button button = findViewById(R.id.button);
        button.setOnClickListener(this);

    }

    //这是个回调函数,在绑定service的时候要用到的
    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i("aaron", "Service has connected");
            //返回的binder转换成你的接口
            iRemoteService = IRemoteService.Stub.asInterface(service);
        }

        //正常unbindservice是不走这的
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i("aaron", "Service has disconnected");
            iRemoteService = null;
        }
    };


    @Override
    protected void onResume() {
        Intent intent = new Intent();
        //客户端service的报名
        intent.setPackage("com.example.myaidl");
        //之前service定义的action
        intent.setAction("com.example.myaidl.service.action");
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);

        super.onResume();
    }

    @Override
    protected void onDestroy() {
        unbindService(mConnection);

        super.onDestroy();
    }

    @Override
    public void onClick(View v) {
        try {
            int i = iRemoteService.getId();
            Log.i("aaron", "invoke AIDL interface success " + i);
        } catch (RemoteException e) {
            Log.i("aaron", "exception: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

 

先把服务端apk装上,然后运行客户端apk

运行结果:

 

第二种:

描述一下,我们要实现的是传送自定义数据类型。我们这传送的是Person类的数据,里面就包含名字和年龄,比较简单。

直接在第一种方法的项目上做的,所以还留着一些第一种方法的文件。

服务端:

就前面2步比较重要,其他基本一样和上面的例子。

1.添加数据类型的AIDL 

这个和上面介绍的不太一样,这个AIDL不是用来和客户端通讯的,只是为了在AIDL中能使用自定义类型的数据。

新建一个Person.aidl文件

代码如下

// Person.aidl
package com.example.myaidl;

parcelable Person;


代码很简单,就一行。

2.定义自定义数据类型

注意:这里的自定义类要和上面的那个aidl的名字,包名都要一样。

package com.example.myaidl;

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

public class Person implements Parcelable {
    private String name;
    private String age;

    public Person(String name, String age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "name: "+name+"  age: "+age;
    }

    //下面都是自动生成的,也是必须要实现的

    protected Person(Parcel in) {
        name = in.readString();
        age = in.readString();
    }

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

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

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

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

下面开始的步骤基本和第一个例子一样

3.新建一个AIDL

这个AIDL接口是用来和客户端通讯的。这里就定义了2个方法,一个获取所有的Person数据,一个是根据指定名字,返回指定Person数据。

注意:这里要导入对应的Person的引用。不然会报aidl'' finished with non-zero exit value 1错误。如果Person.aidl和Person.java包名不一样也会报错。

// IPersonManager.aidl
package com.example.myaidl;

// Declare any non-default types here with import statements
import com.example.myaidl.Person;

interface IPersonManager {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

    List<Person> getAll();
    List<Person> getByName(String name);
}

 

 

4.创建service,把接口暴露给客户端

        <service
            android:name=".PersonService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.RESPOND_VIA_MESSAGE"/>
            </intent-filter>
        </service>

这里就简单的弄了一点数据。

package com.example.myaidl;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

import java.util.ArrayList;
import java.util.List;

public class PersonService extends Service {
    static List<Person> persons=new ArrayList<>();

    static {
        Person p1=new Person("bob","20");
        Person p2=new Person("king","20");
        Person p3=new Person("leif","30");
        persons.add(p1);
        persons.add(p2);
        persons.add(p3);
    }

    public PersonService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return binder;
    }

    private final IPersonManager.Stub binder=new IPersonManager.Stub() {
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }

        @Override
        public List<com.example.myaidl.Person> getAll() throws RemoteException {
            return persons;
        }

        @Override
        public List<com.example.myaidl.Person> getByName(String name) throws RemoteException {
            List<Person> list=new ArrayList<>();
            for(Person p:persons){
                if(p.getName().equals(name))
                    list.add(p);
            }
            return list;
        }
    };
}

客户端:

客户端的方法和第一个例子基本一样,只是多拷贝点文件。

1.拷贝AIDL和自定义类

这里要把Person.aidl Person.java IPersonManager.aidl都拷贝过来。

注意:包名要和服务端一样

2.绑定service

和之前一样,绑定service,然后实例化一个aidl,直接用。

界面比较简单,不上代码了。就是2个按钮,一个获取所以数据,一个根据edittext中输入的名字来获取数据。

package com.example.myaidlclient;

import android.content.ComponentName;
import android.content.Context;
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.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import com.example.myaidl.IPersonManager;
import com.example.myaidl.Person;

import java.util.List;

public class Main2Activity extends AppCompatActivity implements View.OnClickListener {
    private Button button,button1;
    private EditText editText;
    private IPersonManager iPersonManager;

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

        button=findViewById(R.id.button2);
        button.setOnClickListener(this);
        button1=findViewById(R.id.button3);
        button1.setOnClickListener(this);
        editText=findViewById(R.id.editText);
    }

    private ServiceConnection mConnection=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i("aaron", "Service has connected");
            iPersonManager=IPersonManager.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i("aaron", "Service has disconnected");
            iPersonManager=null;
        }
    };

    @Override
    protected void onResume() {
        Intent intent=new Intent();
        intent.setPackage("com.example.myaidl");
        intent.setAction("android.intent.action.RESPOND_VIA_MESSAGE");
        bindService(intent,mConnection, Context.BIND_AUTO_CREATE);

        super.onResume();
    }

    @Override
    protected void onDestroy() {
        unbindService(mConnection);

        super.onDestroy();
    }

    @Override
    public void onClick(View v) {
        if(v==button){
            try {
                List<Person> all=iPersonManager.getAll();
                for (Person p:all){
                    Log.i("aaron","All person "+p);
                }
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }else if(v==button1){
            String name=editText.getText().toString();
            try {
                List<Person> list=iPersonManager.getByName(name);
                if(list.isEmpty()){
                    Log.i("aaron","no "+name);
                }else {
                    for (Person p:list){
                        Log.i("aaron","person "+p);
                    }
                }
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }
}

 

运行结果:

 

这里也可以在调用接口的时候传递自定义数据类型,当然你还得模仿Person这样写一个aidl和一个java。比如下面,根据人来查询对应的宠物。

在定义接口的时候如果参数不是标准数据类型,要在前面加in out inout。

in表示输入型参数(Server可以获取到Client传递过去的数据,但是不能对Client端的数据进行修改) out表示输出型参数(Server获取不到Client传递过去的数据,但是能对Client端的数据进行修改) inout表示输入输出型参数(Server可以获取到Client传递过去的数据,但是能对Client端的数据进行修改)。

interface IPetManager {

    Pet getPet(in Person p);

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值