Android之AIDL跨进程通信——IPC机制(二)

本文主要记录Android Studio下AIDL的实现流程

一、服务端实现

1.创建Book类
Book类在包名对应根目录下(这里包名为com.example.lgf.aidl),否则会有问题,Book类在AIDL中用到,因此要实现Parcelable接口,代码如下:

package com.example.lgf.aidl;

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

public class Book implements Parcelable {
    public int index;
    public String name;

    public Book(int index, String name) {
        this.index = index;
        this.name = name;
    }

    protected Book(Parcel in) {
        index = in.readInt();
        name = in.readString();
    }

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

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

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

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

2.创建IBookManager.aidl文件
在Project模式下,右键module中的任何文件,然后选择New–>AIDL–>AIDL File,如下图:
这里写图片描述
然后,在弹出的对话框中输入AIDL文件名,这里以IBookManager为例,如下图
这里写图片描述
输入文件名后会在main下生成aidl目录并生成对应包名和AIDL文件,如下图
这里写图片描述
修改IBookManager.aidl文件,去除默认方法,添加addBook方法和getBookList方法,代码如下:

// IBookManager.aidl
package com.example.lgf.aidl;

// Declare any non-default types here with import statements
import com.example.lgf.aidl.Book; // 1

interface IBookManager { 
   void addBook(in Book book); // 2
   List<Book> getBookList();
}

需要注意的是,上面代码注释中,标记1:表示需要导入所用到的类,因为这里用到了Book类;标记2:除了基本数据类型外,其它类型的参数必须标上方向(in、out或者inout,in表示输入型参数,out表示输出型参数,inout表示出入输出型)。
3.创建Book.aidl文件

如果AIDL文件中用到了自定义的Parcelable对象,则须创建一个和它同名的AIDL文件

因为IBookManager.aidl文件中用到了自定义的Parcelable对象Book,因此必须创建和Book同名的Book.aidl文件,在IBookManager.aidl所在包中右键选择New–>File,在弹出的对话框中输入Book.aidl,然后添加如下代码:

package com.example.lgf.aidl;
parcelable Book; 

AIDL中每个实现了Parcelable接口的类都需要按照上面代码这种方式去创建相应的AIDL文件,并声明那个类为parcelable。
4.编译项目
执行上述操作后编译项目,然后会在相应module的 build/generated/source/aidl/debug/包名 下生成相应的类,如下图:
这里写图片描述
5.远程服务端实现
创建Binder对象并在onBind返回它,这个对象继承自IBookManager.Stub并实现了它内部的AIDL方法。

package com.example.lgf.aidl;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;

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

public class BookManagerService extends Service {
    private List<Book> bookList = new ArrayList<>();
    private Binder binder = new IBookManager.Stub() {
        @Override
        public void addBook(Book book) throws RemoteException {
            bookList.add(book);
        }

        @Override
        public List<Book> getBookList() throws RemoteException {
            return bookList;
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        bookList.add(new Book(1, "JAVA"));
        bookList.add(new Book(2, "Android"));
    }

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

6.注册Service
在AndroidManifest.xml中添加如下代码

<service android:name=".BookManagerService" android:exported="true"/>

自此远程服务端算是搞好了。

二、客户端实现

客户端按多进程是否属于同一应用的实现又稍微有点不一样。
1.同一应用的不同进程
如果是同一应用的不同进程,则需要将服务端的service注册增加android:process属性,如下:

<service android:name=".BookManagerService" android:process=":remote"/>

此时,同一module中,客户端实现代码如下:

package com.example.lgf.aidl;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

import java.util.List;

public class MainActivity extends AppCompatActivity {
    private IBookManager iBookManager;
    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iBookManager = IBookManager.Stub.asInterface(service);
            try {
                iBookManager.addBook(new Book(3, "Kotlin"));
                List<Book> bookList = iBookManager.getBookList();
                Log.d("MainActivity", "book size-->" + bookList.size());
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bindService(new Intent(this, BookManagerService.class), serviceConnection, BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(serviceConnection);
    }
}

2.不同应用
如果是不同的应用,则需要把服务端的aidl文件以及相关的实现Parcelable类,原原本本的复制到客户端,包名也要一样,如下图:
这里写图片描述
接着编译下工程,然后会在module的 build/generated/source/aidl/debug/包名 下生成相应的类,和之前的一样。
最后客户端的实现代码如下:

package com.example.lgf.myapplication;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

import com.example.lgf.aidl.Book;
import com.example.lgf.aidl.IBookManager;

import java.util.List;

public class MainActivity extends AppCompatActivity {
    private IBookManager iBookManager;
    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iBookManager = IBookManager.Stub.asInterface(service);
            try {
                iBookManager.addBook(new Book(3, "Python"));
                List<Book> bookList = iBookManager.getBookList();
                Log.d("MainActivity", "book size-->" + bookList.size());
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent(Intent.ACTION_MAIN); // 1
        ComponentName componentName = new ComponentName("com.example.lgf.aidl", "com.example.lgf.aidl.BookManagerService"); // 2
        intent.setComponent(componentName); // 3
        bindService(intent, serviceConnection, BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(serviceConnection);
    }
}

此处需要注意的是,代码注释中,标注1:意图要用Intent.ACTION_MAIN;标注2:ComponentName构造方法参数中,第一个为服务端的包名,第二个是要绑定的服务端的服务名;标注3:要启动其它应用组件需要调用setComponent方法,因为Android5.0以后不用隐式启动。
另外,服务端的MainActivity需要修改服务的启动方式,改为如下:

package com.example.lgf.aidl;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent service = new Intent(this, BookManagerService.class);
        startService(service);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Intent service = new Intent(this, BookManagerService.class);
        stopService(service);
    }
}

运行客户端前先运行服务端app,自此,不同应用的AIDL通信已完成。

附:

示例代码:[email protected]:Geroff/AIDLTest.git的develop分支,tag中v1是同一应用多进程的AIDL,v2是不同应用的AIDL

猜你喜欢

转载自blog.csdn.net/fengyulinde/article/details/79143681