美文网首页
很高兴能再次遇见您——AIDL

很高兴能再次遇见您——AIDL

作者: 夏广成 | 来源:发表于2017-07-30 15:12 被阅读36次

一:aidl与messenger的使用区别

  • aidl与messenger都是使用在进程间通信的方式,底层都是Binder。不是进程间通信的可以直接使用Binder。
  • messenger底层使用的是aidl结构。
  • messenger服务端串行执行任务。
  • aidl可以实现并发操作,但是要注意线程安全。aidl还可以调用远程服务的方法,messenger则不可以。
  • aidl的同步主要是在aidl接口在service中的实现时添加。

二:一个简单的aidl创建流程

(一):创建aidl文件

image.png

(二):创建远程服务

注意aidl接口的方法,是需要线程安全的。


image.png

(三):将远程的aidl包拷贝到本地项目

后面还会介绍如何使用parcelable对象,其中实现parcelable对象的类,也需要写一个aidl文件。


(四):绑定远程服务

在调用aidl接口方法的时候,需要注意这个方法是耗时操作。


image.png

三:远程启动服务的注意事项

aidl一般是用在两个进程中,如果使用在两个app中,那么要怎么从一个app启动另一个app的远程服务呢?在android 5.0之后,系统规定要使用显示启动所有的service,否则就会抛出异常。因此就有下面两种启动方式

(一)设置过滤器,google并不建议我们这么做

java.lang.IllegalArgumentException: Service Intent must be explicit: Intent { act=com.xia }

<service android:name=".MyService"
           >
            <intent-filter>
                <action android:name="com.xia"/>
            </intent-filter>
</service>

 intent.setAction("com.xia");
intent.setPackage("xiaguangcheng.com.local");

由于service设置了过滤器,那么exported就默认为true了。

(二)使用全类名打开service,主要要把允许其他app使用设置为true

java.lang.SecurityException: Not allowed to bind to service Intent { cmp=xiaguangcheng.com.local/.MyService }
 <service android:name=".MyService"
            android:exported="true">
  </service>
  
intent.setComponent(new ComponentName("xiaguangcheng.com.local","xiaguangcheng.com.local.MyService"));

由于没有设置过滤器,因此需要显示指定exproted=true。


四:创建一个略复杂的aidl

(一)aidl支持的数据类型

  • 基本数据类型
  • String和CharSequence
  • ArrayList,元素必须被aidl支持
  • HashMap,元素必须被aidl支持
  • Parcelable,所有实现了Parcelable接口的对象
  • aidl接口本身也能在aidl文件中使用

(二)使用parcelable接口的对象

  • 我们要在java包中创建一个Book.java文件实现parcelable接口
  • 我们还要在aidl包中创建一个同名的aidl文件Book.aidl,并在其中声明parcelable Book;同时手动导入Book.java的包名。

(三)使用RemoteCallbackList删除跨进程接口

public class BookManagerService extends Service {
    public static final String TAG="BMS";
    //读写分离,最终一致性,保障并发安全
    private CopyOnWriteArrayList<Book> mBookList=new CopyOnWriteArrayList<>();
    private AtomicBoolean mIsServiceDestoryed=new AtomicBoolean(false);
    //解决因为aidl的序列化问题,导致传递过来的对象,已非客户端的对象。这个类则解决了这个问题。
    private RemoteCallbackList<IBookManagerNewBookArravied> mListenerList=
        new RemoteCallbackList<>();
    @Override
    public void onCreate() {
        super.onCreate();
        mBookList.add(new Book("西游记",111));
        mBookList.add(new Book("红楼梦",222));
        new Thread(new ServiceWorker()).start();
    }

    private Binder mBinder=new IBookManager.Stub(){

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

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

        @Override
        public void registerListener(IBookManagerNewBookArravied listener) throws RemoteException {
            mListenerList.register(listener);
        }

        @Override
        public void unRegisterListener(IBookManagerNewBookArravied Listener) throws RemoteException {
            mListenerList.unregister(Listener);
        }
    };
    public BookManagerService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return mBinder;
    }

    private class ServiceWorker implements Runnable {
        @Override
        public void run() {
            while(!mIsServiceDestoryed.get()){
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                int bookId= mBookList.size()*111;
                Book newBook=new Book("bookName:"+bookId,bookId);
                try {
                    onNewBookArrrived(newBook);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void onNewBookArrrived (Book newBook)throws RemoteException {
        mBookList.add(newBook);
        final int N=mListenerList.beginBroadcast();
        for(int i=0;i<N;i++){
            IBookManagerNewBookArravied iBookManagerNewBookArravied = mListenerList.getBroadcastItem(i);
            if(iBookManagerNewBookArravied!=null){
                iBookManagerNewBookArravied.onNewBookArrived(newBook);
            }
        }
        mListenerList.finishBroadcast();
    }

    @Override
    public void onDestroy() {
        mIsServiceDestoryed.set(true);
        super.onDestroy();
    }
}

五:如何判断Binder连接是否中断

在绑定服务完成之后,我们要给binder设置一个死亡代理。即通过IBinder.linkToDeath(mDeathRecipient,0)来设置。其中这个死亡接收者有一个binderDied的回调。当binder中断,就需要在这个回调中,取消之前绑定死亡代理的那个binder,重新绑定服务,绑定死亡代理。

    IM im;
    private IBinder.DeathRecipient mDeathRecipient=new IBinder.DeathRecipient(){
        @Override
        public void binderDied() {
            if(im==null){
                return;
            }
            im.asBinder().unlinkToDeath(mDeathRecipient,0);
            im=null;

           connect();

        }
    };
……
 public void connect(){
        Intent intent=new Intent("com.abc");
        intent.setPackage("com.xiaguangcheng.aidl");
        bindService(intent, new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                im=IM.Stub.asInterface(service);
                try {
                    service.linkToDeath(mDeathRecipient,0);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        },BIND_AUTO_CREATE);
    }

相关文章

  • 很高兴能再次遇见您——AIDL

    一:aidl与messenger的使用区别 aidl与messenger都是使用在进程间通信的方式,底层都是Bin...

  • 很高兴能再次遇见您——service

    只有 Activity、服务和内容提供程序可以绑定到服务 — 您无法从广播接收器绑定到服务。 1:Service和...

  • 很高兴遇见您

    “本文参加#迷彩加身,我的军训我来说#活动,本人承诺,文章内容为原创,且未在其他平台发表过。” ...

  • 很高兴,再次遇见你

    算上这次,我参加了两次小白训练营,每次都有不一样的收获。 第一次,在去年3月份,在微信公众号刷到长投学堂9块钱的小...

  • 很高兴再次遇见你

    说起来,我跟她有过一面之缘,但在此之后,再无联系。今年暑假,因为兼职,我们又遇见了,而我对她,也有了更进一步的认识...

  • 很高兴遇见你,再次。

    我没有想到,我会在去西藏的旅游途中遇到我的前男友。为了避免互相认出来的尴尬,我准备拉低自己卫衣的帽子,企图遮盖...

  • 很高兴遇见你,再次

    第二天,我做早操的时候,没有人把我放倒了。 导游说,今天去林芝。 百度上说:林芝市,古称工布,是藏文“...

  • 很高兴遇见你 ,再次。

    中午,妈妈比划着问我什么,我不懂,后来她找了张纸写下给我看:你认识一直护着你的那个男孩吗?一直护着我?男孩?尽管我...

  • 你好,很高兴再次遇见

    读《遇见未知的自己》 7月份读的是张德芬老师的《遇见未知的自己》,在这本书里,作者借助故事讲述主人公突破层层障碍探...

  • 朋友,很高兴再次遇见你

    文|过云雨 494/500 回忆一经放出闸口,就如洪水泛滥,席卷而来,猛然回到了当时的情景里。 因为一次点赞,重新...

网友评论

      本文标题:很高兴能再次遇见您——AIDL

      本文链接:https://www.haomeiwen.com/subject/igtklxtx.html