最近温习了AIDL的相关知识,写在这里,记录下来.

首先,先说下跨进程通信的方式有哪些。进程间的通信我们可以使用Messenger,可以在Intent中附加extras来传递信息,或者通过共享文件的方式来共享数据,还可以使用Binder方式来跨进程通信,也可以使用ContentProvider来进行跨进程的数据传递,通过网络的话使用socket也可以实现跨进程通信。

本章博客主要使用AIDL这种方式来进行进程间的通信,AIDL可以处理大量的并发请求,这是通过Messenger不能实现的。Messenger主要是为了传递信息的,如果调用服务端的方法的话,它也是不能做到的。但是可以使用AIDL来调用服务端的方法。

步骤:

1.服务端:

建立一个Service来监听客户端的连接请求,然后创建一个AIDL文件,将暴露给客户端的接口在这个AIDL文件中声明,最后在Service中实现这个AIDL接口即可。

2.客户端:

通过bindService()绑定客户端,将服务端返回的Binder对象转化成AIDL接口所属的类型,就可以在客户端调用AIDL中的方法了。

3.创建AIDL文件:

AIDL文件支持的数据类型:

基本数据类型、

String和CharSequence、 
 List:只支持ArrayList、 
 Map:只支持HashMap 
 parcelable:所有实现了parcelable接口的对象、 
 AIDL:所有AIDL接口本身也可以在AIDL文件中使用

注:如果AIDL文件中用到了自定义的parcelable对象,那么,必须新建一个和它同名的AIDL文件,并在其中声明它为parcelable类型

具体实现:

创建bean类

package org.superzhao.aidltest;

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

public class User implements Parcelable {
    private int userid;
    private String username;

    public User(int userid, String username) {
        this.userid = userid;
        this.username = username;
    }


    protected User(Parcel in) {
        userid = in.readInt();
        username = in.readString();
    }

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

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


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

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

    @Override
    public String toString() {
        return "userid:" + userid +  ", username:" + username;
    }
}

创建AIDL文件:

IUserManager.aidl

// IUserManager.aidl
package org.superzhao.aidltest;

// Declare any non-default types here with import statements
import org.superzhao.aidltest.User;
interface IUserManager {
     List<User> getUserList();
     void addUser(in User user);
}

user.aidl

// User.aidl
package org.superzhao.aidltest;

   parcelable User;


注:在创建完成aidl文件后,记得点击同步按钮或者clean project,否则在service端不能调用aidl中的方法,因为找不到。

Service端的实现:

package org.superzhao.aidltest;

public class UserManagerService extends Service {

    private static final String TAG = "UMS";

    //在这个boolean值变化期间,不允许任何的插入操作,保持操作的原子性
    private AtomicBoolean mIsServiceDestoryed = new AtomicBoolean(false);

    //CopyOnWriteArrayList是支持并发读写的List,自动进行线程同步
    private CopyOnWriteArrayList<User> mUserList = new CopyOnWriteArrayList();

    private CopyOnWriteArrayList<IOnNewUserArrivedListener> mListenerList = new CopyOnWriteArrayList();

    @Override
    public void onCreate() {
        super.onCreate();
        mUserList.add(new User(1,"jobs"));
        mUserList.add(new User(2,"Mike"));
    }

//实现Stub中的抽象方法
    private Binder mBinder = new IUserManager.Stub(){
       //返回所有的用户
        @Override
        public List<User> getUserList() throws RemoteException {
            return mUserList;
        }

        //添加用户
        @Override
        public void addUser(User user) throws RemoteException {
            mUserList.add(user);
        }

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

注:AIDL方法实在服务端的Binder线程池中执行的,因此当多个客户端同时连接的时候,会存在多个线程同时访问的情形,所以要在AIDL方法中处理线程同步,CopyOnWriteArrayList可以进行自动的线程同步。

客户端的实现:

package org.superzhao.aidltest;

public class UserManagerActivity extends Activity {

    private static final String TAG = "UMA";
    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            IUserManager userManager = IUserManager.Stub.asInterface(service);
            try {
                mRemoteUserManager = userManager;
                List<User> list = userManager.getUserList();
                Log.i(TAG,"query list" + list.getClass().getCanonicalName());
                Log.i(TAG,"query User list" + list.toString());
                User user = new User(3,"Tom");
                userManager.addUser(user);
                List<User> newList = userManager.getUserList();
                Log.i(TAG,"query User newList" + newList.toString());

            } 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(this,UserManagerService.class);
        bindService(intent,mConnection,BIND_AUTO_CREATE);
    }

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

总结一下:

使用AIDL的大致流程:

首先创建一个Service和一个AIDL接口,接着创建一个类继承自AIDL接口中的Stub类并实现Stub中的抽象方法,在Service的onBind方法中返回这个类的对象,然后客户端就可以绑定服务端的Service,建立连接后就可以访问远程服务端的方法了