欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

进程间通信学习系列(二)——简单了解Binder机制

程序员文章站 2024-03-24 08:19:58
...

 

进程间通信学习系列(一)——IPC简介


Binder机制太复杂了,本文只是简单的对Binder进行了解。

在Android中Binder是一个类,实现了IBinder接口,在Binder机制中还有两个重要角色Binder驱动(在内核中)和ServiceManager,这两部分Android平台已经实现,我们不必关心,当然有兴趣的童鞋可以研究下。本文主要学习了解应用层的Client和Service相关的Binder知识。

Messenge,ContentProvider等底层实现都是AIDL,所以以AIDL的简单实现来学习Binder机制。

需求:图书管理系统中,1.需要查询图书列表;2.添加新书到图书库中。

先看一下目录结构:

进程间通信学习系列(二)——简单了解Binder机制












首先新建一个Book类,并实现Parcelable序列化接口(Android Studio一键生成序列化代码插件),如下:

public class Book implements Parcelable {
    private double price;
    private long bookId;
    private String bookName;

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeDouble(this.price);
        dest.writeLong(this.bookId);
        dest.writeString(this.bookName);
    }

    public Book() {
    }

    protected Book(Parcel in) {
        this.price = in.readDouble();
        this.bookId = in.readLong();
        this.bookName = in.readString();
    }

    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];
        }
    };
}
新建IBookManager.aidl文件,生命两个接口:

package anyan.com.ipcdemo.aboutaidl;
//注意导入Book类(手动导入)
import anyan.com.ipcdemo.aboutaidl.Book;

interface IBookManager {
    List<Book> getBookList();//查询图书列表
    void addBook(in Book book);//添加新图书
}

因为在IBookManager.aidl文件中使用了非基本数据类型,所以Book类不仅要实现序列化接口,还要新建一个Book.aidl文件(至于为什么,我也不知道),注意这个Book.aidl文件的全路径包名要与Book.java的全路径包名一致,否则编译会报错。内容如下:

package anyan.com.ipcdemo.aboutaidl;

parcelable Book;
Rebuild project成功后再app/build/generated/source/aidl/debug/包名 目录下回生成一个IBookManager.java文件,这是AS帮我们自动生成的,这里使用了代理模式(可简单了解一下,Java设计模式-代理模式实现及原理)主要分析这里的代码:包含两个接口getBookList()和addBook(),可以看到这两个接口就是我们在IBookManager.aidl文件中所声明的。一个内部类Stub,继承Binder实现IBookManager接口。Stub类里面还有一个内部类Proxy也实现了IBookManager接口,这个就是Stub类(也就是Binder)的代理类。

public interface IBookManager extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements anyan.com.ipcdemo.aboutaidl.IBookManager {
        //Binder的唯一标识,一般用类名表示
        private static final java.lang.String DESCRIPTOR = "anyan.com.ipcdemo.aboutaidl.IBookManager";

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

        /**
         * Cast an IBinder object into an anyan.com.ipcdemo.aboutaidl.IBookManager interface,
         * generating a proxy if needed.
         * 将IBinder对象转换成IBookManager接口并返回
         * 这种转换区分进程,如果是在同一进程,直接返回服务端的Stub对象;
         * 如果不在同一进程,则返回代理对象Stub.Proxy;
         */
        public static anyan.com.ipcdemo.aboutaidl.IBookManager asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof anyan.com.ipcdemo.aboutaidl.IBookManager))) {
                return ((anyan.com.ipcdemo.aboutaidl.IBookManager) iin);
            }
            return new anyan.com.ipcdemo.aboutaidl.IBookManager.Stub.Proxy(obj);
        }

        @Override
        public android.os.IBinder asBinder() {
            return this;
        }

        /**
         * 该方法在服务端的Binder线程池中执行,注意采用同步方法
         * @param code 确定客户端请求的目标方法是哪个
         * @param data 目标方法所需参数数据
         * @param reply 目标方法返回数据
         * @param flags
         * @return
         * @throws android.os.RemoteException
         */
        @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_getBookList: {
                    data.enforceInterface(DESCRIPTOR);
                    java.util.List<anyan.com.ipcdemo.aboutaidl.Book> _result = this.getBookList();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;
                }
                case TRANSACTION_addBook: {
                    data.enforceInterface(DESCRIPTOR);
                    anyan.com.ipcdemo.aboutaidl.Book _arg0;
                    if ((0 != data.readInt())) {
                        _arg0 = anyan.com.ipcdemo.aboutaidl.Book.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
                    this.addBook(_arg0);
                    reply.writeNoException();
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        //代理对象
        private static class Proxy implements anyan.com.ipcdemo.aboutaidl.IBookManager {
            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;
            }

            /**
             * 该方法在客户端执行,
             * @return
             * @throws android.os.RemoteException
             */
            @Override
            public java.util.List<anyan.com.ipcdemo.aboutaidl.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<anyan.com.ipcdemo.aboutaidl.Book> _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    //调用远程请求,当前线程挂起,服务端OnTransact()方法会被调用,
                    mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
                    //当前线程继续执行,取出结果
                    _reply.readException();
                    _result = _reply.createTypedArrayList(anyan.com.ipcdemo.aboutaidl.Book.CREATOR);
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            @Override
            public void addBook(anyan.com.ipcdemo.aboutaidl.Book book) 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 ((book != null)) {
                        _data.writeInt(1);
                        book.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }
        
        //方法的id
        static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }

    public java.util.List<anyan.com.ipcdemo.aboutaidl.Book> getBookList() throws android.os.RemoteException;

    public void addBook(anyan.com.ipcdemo.aboutaidl.Book book) throws android.os.RemoteException;
}
如下图所示:

进程间通信学习系列(二)——简单了解Binder机制









接着看具体怎么使用,创建一个BookManagerService类:

public class BookService extends Service {
    public BookService() {
    }

    //支持并发读写
    private CopyOnWriteArrayList<Book> bookList = new CopyOnWriteArrayList<>();

    private IBookManager.Stub binder = new IBookManager.Stub() {
        @Override
        public List<Book> getBookList() throws RemoteException {
            return bookList;
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            bookList.add(book);
        }
    };

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

在Activity中BindService:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private IBookManager iBookManager;
    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //用到了上面提到了转换方法asInterface,将IBinder转换为接口,
            //同一进程直接返回Stub对象,不同进程返回Proxy代理类
            iBookManager = IBookManager.Stub.asInterface(service);
            try {
                service.linkToDeath(deathRecipient, 0);
                //拿到对象后就可以直接调用方法了
                List<Book> bookList = iBookManager.getBookList();
                Log.e(TAG, "onServiceConnected: " + bookList);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    //死亡代理,binder死亡时会收到通知,回调binderDied方法
    private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            if (iBookManager == null)
                return;
            iBookManager.asBinder().unlinkToDeath(deathRecipient, 0);
            iBookManager = null;
            //重新绑定service
            Intent intent = new Intent(MainActivity.this, BookService.class);
            bindService(intent, conn, BIND_AUTO_CREATE);
        }
    };

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

    }

    public void onClick(View view) {
        Intent intent = new Intent(this, BookService.class);
        bindService(intent, conn, BIND_AUTO_CREATE);
    }
}
至此,简单的Binder机制分析完了,看着可能有点懵,很正常,我是看了好几篇才只是简单的理解了。Fighting !!!



相关标签: Binder Android