android 进程间通信(aidl)

注:由于时间关系目前先写个大概,后续再做完善

1.建立aidl
建立aidl文件夹,在文件夹中添加包tk.huayu.api,包中添加以下文件
IService.aidl

package tk.huayu.api;

import tk.huayu.api.Test; // 同一个包下面的也必须导包

interface IService{
    // in表示这个参数是作为输入参数使用(in/out/inout),作为返回值时不用加
    void fun1(in Test test); 
}

Test.aidl

package tk.huayu.api;

parcelable Test; // 声明Test对象

Test2.aidl

package tk.huayu.api;

parcelable Test2; // 声明Test2对象,这个是Test中包含的一个属性(对象)

2.实现aidl用到的对象
新建包tk.huayu.api,这个包必须和aidl中一模一样。在包中添加如下文件

Test.java

package tk.huayu.api;

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


public class Test implements Parcelable {
    public int testInt=1;
    public String testString="Test";
    public Test2 test2 = new Test2();

    public Test(){
    }

    int getTestInt(){
        return testInt;
    }

    /**
     * 实现Parcelable接口必须实现的方法:
     *
     * @return 描述这一Parcel是起什么作用的,通过这一整形每个bit来描述其类型,一般会返回0
     */
    @Override
    public int describeContents() {
        return 0;
    }

    /**
     * 实现Parcelable接口必须实现的方法:
     * 将类所需要传输的属性写到Parcel里,在这个方法里都是使用writeXXX()写入到Parcel
     * @param dest 提供发送功能的Parcel
     * @param flags 用来指定这样的发送方向,与aidl的in、out、inout三种限定符匹配
     */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        //把该对象所包含的数据写到Parcel
        dest.writeInt(testInt);
        dest.writeString(testString);
        //dest.writeParcelable(test2,flags);
        dest.writeValue(test2);
    }

    /**
     * 这个构造方法用于从序列化数据中取出数据。读取的顺序要和writeToParcel()写入的顺序一致
     * @param source 数据源
     */
    private Test(Parcel source){
        testInt = source.readInt();
        testString = source.readString();
        test2 = (Test2)source.readValue(Test2.class.getClassLoader());
    }

    /**
     * 添加一个静态成员,名为CREATOR,该对象实现了Parcelable.Creator接口
     */
    public static final Parcelable.Creator<Test> CREATOR = new Parcelable.Creator<Test>(){

        /**
         * 从Parcel中读取数据,返回Test对象。读取的顺序要和writeToParcel()写入的顺序一致
         * @param source 数据源
         * @return 接收到的对象(通过数据源创建的一个对象)
         */
        @Override
        public Test createFromParcel(Parcel source){
            return new Test(source);
        }

        /**
         * 用于创建多个这种实现了Parcelable接口的类。创建多个空对象,不能以某个Parcel对象为基础创建,使用默认的类创始化方法。
         * @param size 数组大小
         * @return 数组
         */
        @Override
        public Test[] newArray(int size){
            return new Test[size];
        }
    };
}

Test2.java

package tk.huayu.api;

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


public class Test2 implements Parcelable {
    public int testInt=2;
    public String testString="Test2";

    public Test2(){

    }

    int getTestInt(){
        return testInt;
    }

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

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

    private Test2(Parcel source){
        testInt = source.readInt();
        testString = source.readString();
    }

    public static final Parcelable.Creator<Test2> CREATOR
            = new Parcelable.Creator<Test2>(){
        @Override
        public Test2 createFromParcel(Parcel source){
            return new Test2(source);
        }

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

3.实现接口
新建包package tk.huayu.demo

MyService .java

package tk.huayu.demo;

import android.app.Service;
import android.os.IBinder;
import android.content.Context;
import tk.huayu.api.IService;

public class MyService extends Service{

    /**
     * 被远程调用,运行在appliction1进程中的Binder_x线程(查看进程号 android.os.Process.myPid())
     */
    public IService.Stub stub = new IServiceInterface();

    public class IServiceInterface extends IService.Stub // 注意实现的一定要是Stub,否者远端调用得到的将是null()
    {
        // 实现AIDL文件中接口的定义的各个方法。
        public void fun1(Test test){ // 不再注明in,添加public
            ... // 代码略
            Log.d("IService","fun1:"+test);
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ... // 代码略
    }
    @Override
    public IBinder onBind(Intent intent) {
        Log.d("MyService ", "onBind "+android.os.Process.myPid());
        return stub;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d("MyService ", "onUnbind");
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}

4.声明service
AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest ...
    >
    <!-- 添加service外部访问许可(不添加也可以,只是提示警告)。当然,如果service添加了许可,那么客户端也要添加许可
            <uses-permission android:name="tk.huayu.edog"/>, 否则客户端访问时将抛出异常 -->
    <permission android:protectionLevel="normal" android:name="tk.huayu.demo"/>
    <application ...
        >
        <!-- 声明service,要添加 android:exported="true"否则service是不允许外部的应用进行远程调用
        android:process=":remote" // 添加这边表示service在独立的进程运行 -->
        <service
            android:name="tk.huayu.demo.MyService"
            android:exported="true"
            android:permission="tk.huayu.demo"
            />
        ...
    </application>
</manifest>

5.编写客户端
将service的aidl包和api包拷贝到客户端app中(包名不能改变)

MainActivity.java

public class MainActivity extends Activity {
    private ServiceConnection serviceConnection = new ServiceConnection(){
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d("Client","onServiceConnected "+name+"IBinder "+service);
            IService service = IService.Stub.asInterface(service);
            if(service!=null)
            {
                try {
                    Log.d("Client", "call fun1");
                    service.fun1(new Test());
                } catch (RemoteException e) {
                    e.printStackTrace();
                    Log.d("Client", "service is bad");
                }
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d("Client","onServiceConnected "+name);
        }
    };  

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        Intent i = new Intent();
        i.setClassName("tk.huayu.demo","tk.huayu.demo.MyService");
        this.context.bindService(i, serviceConnection, Context.BIND_AUTO_CREATE);
        Log.d("Client", "service bind "+android.os.Process.myPid());
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(serviceConnection);
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest ...
    >
    <!-- 添加许可 -->
    <uses-permission android:name="tk.huayu.demo"/>
    <application ...
        >
        ...
    </application>
</manifest>

注:也可以在客户端实现类似IService接口,将接口实例通过参数注册到service,这样service也能远程调用客户端的函数,如果客户端有多个(一般也是有多个)可以使用RemoteCallbackList进行批量回调。

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页