Android实现IPC进程间通信的6种方式 (五)AIDL篇

接前四篇
基础篇
bundle篇
文件共享篇
Messenger篇

AIDL( Android Interface Definition Language)Android接口定义语言。上篇中的Messenger其实是一种特殊的AIDL,系统帮我们进行了封装,让我们使用起来更方便快捷。但是Messenger是串行处理消息的,不适合大量并发的情况;并且Messenger只能传递数据,客户端不能调用服务端的方法,而这些AIDL都是可以实现的
本篇我们来用AIDL实现进程间通信
服务端
1)创建我们需要传递数据类的java文件Book,实现Parcelable接口

public class Book implements Parcelable {
    public String name;
    public Book(String name){
        this.name = name;
    }

    protected Book(Parcel in) {
        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.writeString(name);
    }

    @Override
    public String toString(){
        return " \n Book { " + "name = " + name + "}";
    }
}

2)创建传递数据的AIDL文件。
在对应的目录上,右键就可以创建AIDL文件
在这里插入图片描述
创建的Book.aidl

package aidl.example.com.aidlpractise;

parcelable Book;

注意一下,创建的Book.aidl文件所在的包要与Book.java的包名相同
在这里插入图片描述

3)创建传递方法的AIDL接口
创建的IMyAidlInterface.aidl

package aidl.example.com.aidlpractise;

import aidl.example.com.aidlpractise.Book;

interface IMyAidlInterface {
    void addBook(in String name);//非基本类型数据需要标注in out inout
    List<Book> getBookList();
}

4)build代码,系统自动为我们生成java文件接口
系统为我们创建的java文件目录在app --> build --> genersted --> source --> aidl --> debug --> 接口aidl包名
在这里插入图片描述
打开文件看一下,是这样的

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: D:\\Document\\former\\Demo\\AndroidStudio_demo\\AIDLPractise\\app\\src\\main\\aidl\\aidl\\example\\com\\aidlpractise\\IMyAidlInterface.aidl
 */
package aidl.example.com.aidlpractise;
public interface IMyAidlInterface extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements aidl.example.com.aidlpractise.IMyAidlInterface
{
private static final java.lang.String DESCRIPTOR = "aidl.example.com.aidlpractise.IMyAidlInterface";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an aidl.example.com.aidlpractise.IMyAidlInterface interface,
 * generating a proxy if needed.
 */
public static aidl.example.com.aidlpractise.IMyAidlInterface asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof aidl.example.com.aidlpractise.IMyAidlInterface))) {
return ((aidl.example.com.aidlpractise.IMyAidlInterface)iin);
}
return new aidl.example.com.aidlpractise.IMyAidlInterface.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_addBook:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
this.addBook(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_getBookList:
{
data.enforceInterface(DESCRIPTOR);
java.util.List<aidl.example.com.aidlpractise.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements aidl.example.com.aidlpractise.IMyAidlInterface
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public void addBook(java.lang.String name) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(name);
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
//非基本类型数据需要标注in out inout

@Override public java.util.List<aidl.example.com.aidlpractise.Book> getBookList() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<aidl.example.com.aidlpractise.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(aidl.example.com.aidlpractise.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public void addBook(java.lang.String name) throws android.os.RemoteException;

public java.util.List<aidl.example.com.aidlpractise.Book> getBookList() throws android.os.RemoteException;
}

5)服务端创建一个Service来监听客户端的连接请求,并在Service实现AIDL接口
// MyAIDLService.java

public class MyAIDLService extends Service {
    private final String TAG = this.getClass().getSimpleName();

    List<Book> myBookList = null;

    private IBinder mIBinder = new IMyAidlInterface.Stub() {
        @Override
        public void addBook(String name) throws RemoteException {
            myBookList.add(new Book(name));
        }

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

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        myBookList = new ArrayList<>();
        Log.d(TAG,"MyAIDLService onBind");
        return mIBinder;
    }
}

到此,我们就把服务端的代码完成了
客户端
客户端要做的事情简单一点
1)绑定服务端的Service
2)绑定成功后,将服务端返回的Binder转换为AIDL接口所属的类型
3)在需要的地方调用AIDL接口的方法实现进程间通信
我是将客户端放在一个Activity中,点击界面的button随机产生一本书,调用addBook(),然后调用getBookList()返回所有的数目列表,显示在TextView中

public class MainActivity extends AppCompatActivity {

    private IMyAidlInterface iMyAidlInterface;
    private LinearLayout layout;
    private TextView textView;
    private Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        layout = new LinearLayout(getApplicationContext());
        layout.setOrientation(LinearLayout.VERTICAL);
        layout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        setContentView(layout);

        textView = new TextView(getApplicationContext());
        textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        layout.addView(textView);

        button = new Button(getApplicationContext());
        button.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        button.setText("增加一本书");
        layout.addView(button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Random random = new Random();
                String name = "编程"+random.nextInt(10);
                try{
                    iMyAidlInterface.addBook(name);
                    List<Book> lastBookList = iMyAidlInterface.getBookList();
                    textView.setText(lastBookList.toString());
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        });

        Intent intent = new Intent(getApplicationContext(),MyAIDLService.class);
        bindService(intent,serviceConnection,BIND_AUTO_CREATE);
    }

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
        }

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

Manifest文件
最后在Manifest文件中将service和activity放在不同的进程中

<service
    android:name=".MyAIDLService"
    android:enabled="true"
    android:exported="true"
    android:process="android.aidl.service" />

<activity
    android:name=".MainActivity"
    android:process="android.aidl.client">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>

运行结果
在这里插入图片描述我们目前实现了客户端主动请求服务端,添加和查询书籍。但是实际中我们更希望服务端在有了新书的时候,主动提醒我们新书到了,这种观察者模式要怎么实现呢,下面我们来看看
首先我们需要定义一个OnNewBookArrivedListener的接口,在接口中我们将利用方法newBookArrived将新书发送给订阅者们
//OnNewBookArrivedListener

package aidl.example.com.aidlpractise;

import aidl.example.com.aidlpractise.Book;

interface OnNewBookArrivedListener {
    void newBookArrived(in Book newBook);
}

接下来我们修改IMyAidlInterface.aidl,我们添加订阅和取消订阅接口OnNewBookArrivedListener的分两个方法
//IMyAidlInterface .aidl

package aidl.example.com.aidlpractise;

import aidl.example.com.aidlpractise.Book;
import aidl.example.com.aidlpractise.OnNewBookArrivedListener;

interface IMyAidlInterface {
    void addBook(in String name);
    List<Book> getBookList();
    void registerListener(OnNewBookArrivedListener listener);
    void unRegisterListener(OnNewBookArrivedListener listener);
}

然后我们肯定要修改MyAIDLService的mIBinder,并添加一个循环来模拟新书到来,具体代码如下
//MyAIDLService

public class MyAIDLService extends Service {
    private final String TAG = this.getClass().getSimpleName();
    private RemoteCallbackList<OnNewBookArrivedListener> listeners;//跨进程listener接口要用RemoteCallbackList

    List<Book> myBookList = null;

    private IBinder mIBinder = new IMyAidlInterface.Stub() {
        @Override
        public void addBook(String name) throws RemoteException {
            myBookList.add(new Book(name));
        }

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

        @Override
        public void registerListener(OnNewBookArrivedListener listener) throws RemoteException {
                listeners.register(listener);
                Log.d(TAG,"registerListener");
        }

        @Override
        public void unRegisterListener(OnNewBookArrivedListener listener) throws RemoteException {
            listeners.unregister(listener);
        }
    };

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        myBookList = new ArrayList<>();
        listeners = new RemoteCallbackList<>();
        Log.d(TAG,"MyAIDLService onBind");
        refreshNewBook();
        return mIBinder;
    }

    private Timer timer = new Timer();
    private TimerTask timerTask = new TimerTask() {
        @Override
        public void run() {
            try {
                int N = listeners.beginBroadcast();
                for(int i=0; i< N; i++){//RemoteCallbackList比需采用这种方式遍历
                    OnNewBookArrivedListener listener = listeners.getBroadcastItem(i);
                    listener.newBookArrived(new Book("新书" + new Random().nextInt(10)));
                    Log.d(TAG, "new book arrived");
                }
            }catch (RemoteException e) {
                e.printStackTrace();
            }finally {
                listeners.finishBroadcast();
            }
        }
    };

    private void refreshNewBook() {
        timer.schedule(timerTask,100,2000);
    }
}

接下来就是在客户端添加OnNewBookArrivedListener的监听了
//MainActivity

public class MainActivity extends AppCompatActivity{

    private IMyAidlInterface iMyAidlInterface;
    private LinearLayout layout;
    private TextView textView;
    private Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        layout = new LinearLayout(getApplicationContext());
        layout.setOrientation(LinearLayout.VERTICAL);
        layout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        setContentView(layout);

        textView = new TextView(getApplicationContext());
        textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        layout.addView(textView);

        button = new Button(getApplicationContext());
        button.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        button.setText("增加一本书");
        layout.addView(button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Random random = new Random();
                String name = "编程"+random.nextInt(10);
                try{
                    iMyAidlInterface.addBook(name);//客户端访问服务端方法,客户端会挂起,尽量放在非主线程中
                    List<Book> lastBookList = iMyAidlInterface.getBookList();//客户端访问服务端方法,耗时,尽量放在非主线程中
                    textView.setText(lastBookList.toString());
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        });

        Intent intent = new Intent(getApplicationContext(),MyAIDLService.class);
        bindService(intent,serviceConnection,BIND_AUTO_CREATE);
    }

    private OnNewBookArrivedListener onNewBookArrivedListener = new OnNewBookArrivedListener.Stub() {
        @Override
        public void newBookArrived(Book newBook) throws RemoteException {
            if(textView != null) {
                iMyAidlInterface.addBook(newBook.name);
                List<Book> lastBookList = iMyAidlInterface.getBookList();
                Message message = new Message();
                message.obj= lastBookList.toString();
                message.what = 0;
                handler.sendMessage(message);
            }
        }
    };

    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg){
            switch (msg.what){
                case 0:
                    textView.setText(msg.obj.toString());
            }
        }
    };

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
            try {
                iMyAidlInterface.registerListener(onNewBookArrivedListener);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

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

    @Override
    public void onDestroy(){
        try {
            iMyAidlInterface.unRegisterListener(onNewBookArrivedListener);
            unbindService(serviceConnection);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        super.onDestroy();
    }
}

接下来我们运行代码

在这里插入图片描述
到这里我们就把AIDL的基础知识学习完了

下一篇 ContentProvider实现进程间通信

特别感谢《Android 开发艺术探索》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值