android开发艺术探索3:IPC--AIDL(跨进程)的使用

本文详细介绍了使用AIDL实现Android跨进程通信的过程。包括服务端创建AIDL接口、实现服务及客户端绑定服务并调用远程方法等内容。

AIDL的使用

我们可以使用AIDL来实现跨进程的方法调用,在上一个博客中我们介绍了binder的概念,在binder的基础上我们可以更加容易的理解AIDL。这里先介绍使用aidl来进行进程间通信的流程,分为服务端和客户端两个方面。

  1. 服务端

      服务端首先要创建一个service用来监听客户端的连接请求,然后创建一个AIDL文件,将暴露给客户端的接口在这个AIDL文件中声明,最后再service中实现这个AIDL接口即可。

  1.  
  2. 客户端

    客户端所要做的事情就稍微简单一些,首先需要绑定服务端的setvice,绑定成功后,将服务端返回的binder对象转成AIDL接口所属的类型,接着就可以调用AIDL中的方法了。

   上述只是一个感性的过程,AIDL的实现过程远不止这么简单,接下来会对其中的细节和难点进行详细介绍。

  3.AIDL接口的创建

   首先看AIDL接口的创建,如下所示,我们创建了一个后缀为AIDL的文件,在里面生命了一个接口和两个接口方法。

// IbookManager.aidl
package com.dzx.recyclerviewdemo.aidl;

// Declare any non-default types here with import statements
import com.dzx.recyclerviewdemo.aidl.Book;
interface IbookManager {

    /**
       * 除了基本数据类型,其他类型的参数都需要标上方向类型:in(输入), out(输出), inout(输入输出)
     */
   void addBook(in Book book);
   List<Book> getBookList();
}

在AIDL文件中,并不是所有的数据类型都是可以使用的,那么到底AIDL文件支持哪些数据类型呢?

共 4 种:

  1. Java 的基本数据类型
  2. List 和 Map 
    • 元素必须是 AIDL 支持的数据类型
    • Server 端具体的类里则必须是 ArrayList 或者 HashMap
  3. 其他 AIDL 生成的接口
  4. 实现 Parcelable 的实体

  其中自定义的parcelable对象和AIDL对象必须要显式import进来,不管他们是否和当前的AIDL文件位于同一个包内。

  另外一个需要注意的地方是,如果AIDL文件中用到了自定义的parcelable对象,那么必须新建一个和他同名的AIDL文件并在其中生命他为parcelable类型。在上面ibookmanager中,我们用到了book这个类,所以,必须要创建爱你book.aidl,如下

package com.dzx.recyclerviewdemo.aidl;
//还要和声明的实体类在一个包里,同时注意不要新建aidl文件,因为你会发现,新建不了,
//提示你名称唯一,此时你新建一个file,名字为Person.aidl就可以,需要特别注意下
parcelable Book;

然后还有一个实现了parcelable的book。java类,如下:

package com.dzx.recyclerviewdemo.aidl;

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

/**
 * Created by Administrator on 2018/8/14 0014.
 */

public class Book implements Parcelable{


    public int bookId;
    public String bookName;

    public Book(int bookId, String bookName) {
        this.bookId = bookId;
        this.bookName = bookName;
    }

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(bookId);
        dest.writeString(bookName);

    }
    public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>() {

        @Override
        public Book createFromParcel(Parcel source) {
            return new Book(source);
        }

        @Override
        public Book[] newArray(int size) {

            return new Book[size];
        }
    };
    private Book(Parcel parcel){
        bookId = parcel.readInt();
        bookName = parcel.readString();
    }
}

4.远程服务端service的实现

上面讲述了如何定义AIDL接口,接下来我们就需要实现这个接口了,我们创建一个MyAidlService,的service,代码如下:

public class MyAidlService extends Service {
    private static final String TAG = "MyAidlService";



    private CopyOnWriteArrayList<Book> mBooks;
    private IBinder mIbinder = new IbookManager.Stub(){

        @Override
        public void addBook(Book book) throws RemoteException {
            Log.e("sssssssssssssss", "ssssssssaddBook" );
            mBooks.add(book);
        }

        @Override
        public List<Book> getBookList() throws RemoteException {
            return mBooks;
        }
    };
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        mBooks = new CopyOnWriteArrayList<>();
        Log.e("sssssssssss", "ssssssssonBind" );
        return mIbinder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("sssssssssss", "onDestroy" );
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e("sssssssssss", "onDestroy" );
    }
}

上面这主要看getbooklist和addBook这两个aidl方法的实现,实现过程也比较简单,注意这里采用了CopyOnWriteArrayList,在前面我们提到,AIDL方法啊是在服务端的binder线程池中执行的,因此当多个客户端同时连接的时候,会存在多个线程同时访问的情形,所以我们要子啊AIDL方法中处理线程同步,所以会用到CopyOnWriteArrayList来进行自动的线程同步。

然后我们需要在XML中注册这个service,注意此service是运行在独立进程中的,它和客户端的activity不在同一个进程中,这样就构成了进程间通信的场景:

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

客户端

客户端实现首先要绑定远程服务,绑定成功后将服务端返回的binder赌侠ing转成AIDL接口,然后就可以通过这个接口去调用服务端的远程方法了,代码如下:

public class MainActivity extends AppCompatActivity {

    private List<String>list;

    private IbookManager ibookManager;
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            ibookManager = IbookManager.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

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

        Intent intent = new Intent(MainActivity.this,MyAidlService.class);
        bindService(intent,connection, Service.BIND_AUTO_CREATE);

        startService(intent);

        TextView tv = (TextView)findViewById(R.id.tv);
        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Book book = new Book(1,"android");
                try {
                    ibookManager.addBook(book);
                    List<Book>mList = ibookManager.getBookList();
                    Log.e("sssss","ssssssss mlist = "+mList.toString());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }

            }
        });

  




    }

}

其实大家看起来跟同进程的没啥区别  但是这是多进程的跨进程通信,希望大家了解

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值