Android aidl 案例分析Binder机制

1.在build.gradle 中

main {
    manifest.srcFile 'src/main/AndroidManifest.xml'
    java.srcDirs = ['src/main/java', 'src/main/aidl']
    resources.srcDirs = ['src/main/java', 'src/main/aidl']
    aidl.srcDirs = ['src/main/aidl']
    res.srcDirs = ['src/main/res']
    assets.srcDirs = ['src/main/assets']
}

以免创建aidl 之后程序编译的时候报找不到类 错误。

2.创建一个User.aidl

// Book.aidl
package cn.mugua.com.newaidldemo;

// Declare any non-default types here with import statements
import cn.mugua.com.newaidldemo.User;
 parcelable User;
 系统会自动生成一个aidl文件夹

在当前文件夹下面分别创建 User.Java Book.Java IuserManager.aidl;

public class User implements Parcelable{//

    public int mUserId;
    public String mUserName;
    public boolean mIsmale;
    public Book mBook;

    private User(Parcel in) {
        mUserId = in.readInt();
        mUserName = in.readString();
        mIsmale = in.readInt()==1;
        mBook = in.readParcelable(Thread.currentThread().getContextClassLoader());//这里需要传当前线程的上下文加载器 否则会报找不到类错误
    }

    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(mUserId);
        dest.writeString(mUserName);
        dest.writeInt(mIsmale?1:0);
        dest.writeParcelable(mBook,0);//这里的flag0 或者1 几乎所有时候都为0 表示是否将当前对象作为返回值 如果为1的话资源不会释放
    }

扫描二维码关注公众号,回复: 1497437 查看本文章
// IUserManager.aidl
package cn.mugua.com.newaidldemo;

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

3.运行 或者makeProject 会在Build/generated/source/aidl/debug 下面自动生成一个  

IUserManager.java 

package cn.mugua.com.newaidldemo;

public interface IUserManager extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements cn.mugua.com.newaidldemo.IUserManager {
        private static final java.lang.String DESCRIPTOR = "cn.mugua.com.newaidldemo.IUserManager";

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an cn.mugua.com.newaidldemo.IUserManager interface,
         * generating a proxy if needed.
         */
        public static cn.mugua.com.newaidldemo.IUserManager asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof cn.mugua.com.newaidldemo.IUserManager))) {
                return ((cn.mugua.com.newaidldemo.IUserManager) iin);
            }
            return new cn.mugua.com.newaidldemo.IUserManager.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_addUser: {
                    data.enforceInterface(DESCRIPTOR);
                    cn.mugua.com.newaidldemo.User _arg0;
                    if ((0 != data.readInt())) {
                        _arg0 = cn.mugua.com.newaidldemo.User.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
                    this.addUser(_arg0);
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_getUserList: {
                    data.enforceInterface(DESCRIPTOR);
                    java.util.List<cn.mugua.com.newaidldemo.User> _result = this.getUserList();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements cn.mugua.com.newaidldemo.IUserManager {
            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 addUser(cn.mugua.com.newaidldemo.User user) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    if ((user != null)) {
                        _data.writeInt(1);
                        user.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    mRemote.transact(Stub.TRANSACTION_addUser, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            @Override
            public java.util.List<cn.mugua.com.newaidldemo.User> getUserList() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.util.List<cn.mugua.com.newaidldemo.User> _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getUserList, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.createTypedArrayList(cn.mugua.com.newaidldemo.User.CREATOR);
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

        static final int TRANSACTION_addUser = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_getUserList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }

    public void addUser(cn.mugua.com.newaidldemo.User user) throws android.os.RemoteException;

    public java.util.List<cn.mugua.com.newaidldemo.User> getUserList() throws android.os.RemoteException;
}

通过这个类可以详细的了解Binder 的机制:所有在Binder中传输的接口都需要继承 IInterface 这个类声明了两个方法 就是我们在aidl 中声明的方法
同时它还给这个方法声明了两个id 用来标识 在transact 方法中到底调用的是哪个 方法 。。。后续详解
4.创建一个UserService 
 
 
 
package cn.mugua.com.newaidldemo;

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

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

/**
 * Created by diyang on 2017/12/12.
 */
public class UserService extends Service{
    private static List<User> mUserList = new ArrayList<>();
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new UserBinder();
    }

    public static class UserBinder extends IUserManager.Stub{
        public UserBinder() {
        }

        @Override
        public synchronized void addUser(User user) throws RemoteException {
            if(!mUserList.contains(user)){
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                mUserList.add(user);
            }
        }

        @Override
        public synchronized List<User> getUserList() throws RemoteException {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return mUserList;
        }
    }
}
package cn.mugua.com.newaidldemo;

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

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

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private ServiceConnection mConn;
    private IUserManager mBinder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mConn  = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                mBinder =  IUserManager.Stub.asInterface(service);
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
                mBinder = null;
            }
        };
        bindService(new Intent(this,UserService.class),mConn,BIND_AUTO_CREATE);
        findViewById(R.id.btn_addUser).setOnClickListener(this);
        findViewById(R.id.btn_getUsers).setOnClickListener(this);
    }
private int id = 1;
    @Override
    public void onClick(View v) {
        if(mBinder == null){
            return;
        }
        List<User> users = new ArrayList<>();
        long time = System.currentTimeMillis();
        switch (v.getId()){
            case R.id.btn_addUser:
                try{
                    mBinder.addUser(new User(id,id+"",true,new Book(id,"book"+id)));
                    id++;
                }catch (Exception e){
                    e.printStackTrace();
                }
                break;
            case R.id.btn_getUsers:
                try{
                     users =  mBinder.getUserList();
                }catch (Exception e){
                    e.printStackTrace();
                }
                break;
        }
        long current = System.currentTimeMillis();
        Log.i("during_time",current-time+"");
        Log.i("during_time",users.toString()+"");
    }

    @Override
    protected void onPause() {
        super.onPause();
        if(mConn != null)
        unbindService(mConn);
    }
}
需要注意以下几点
1.这里的mBinder 不能写成是UserBinder 否则会报 不能将Proxy强转为 UserBinder 因为服务端和客户端 不同的进程的时候 Binder 是将数据封装到了Proxy中
 mBinder =  IUserManager.Stub.asInterface(service);
2.运行代码报错 找不到Book 类
 
 
这时候需要将
 
 
private User(Parcel in) {
    mUserId = in.readInt();
    mUserName = in.readString();
    mIsmale = in.readInt()==1;
    mBook = in.readParcelable(Book.class.getClassLoader());
}
最后一行代码改成 Book. class .getClassLoader()

具体原因下次再研究


猜你喜欢

转载自blog.csdn.net/yyo201/article/details/78786678