AIDL使用整理

AIDL 全称:android interface defination language 安卓接口定义语言。适用于进程间通信。

首先创建Book对象

package com.example.test.aidl;

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

import java.io.Serializable;

/**
 * Description:
 */

public class Book implements Parcelable{
    private int bookId;
    private String bookName;

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

    protected Book(Parcel in) {
        bookId = in.readInt();
        bookName = in.readString();
    }

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

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

    public int getBookId() {
        return bookId ;
    }

    public void setBookId(int bookId) {
        this.bookId = bookId;
    }

    public String getBookName() {
        return bookName ;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

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

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

创建Book.aidl文件
在这里插入图片描述
修改Book.aidl内容

package com.example.test.aidl;

parcelable Book;

再创建IBookManager.aidl文件
提供两个方法,addBook和getBookList方法

package com.example.test.aidl;
import com.example.test.aidl.Book;

interface IBookManager {
     List<Book> getBookList();
     void addBook(in Book book);
}

接下来就服务端,创建BookManagerService继承Service,在onCreate()中初始化添加了4本书。并创建一个Binder对象在onBind()中返回。

package com.example.test.aidl;

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

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * Description:
 */

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


    private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();

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

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

    @Override
    public void onCreate() {
        super.onCreate();

        mBookList.add(new Book(1,"西游记"));
        mBookList.add(new Book(2,"红楼梦"));
        mBookList.add(new Book(3,"水浒传"));
        mBookList.add(new Book(4,"三国演义"));
    }

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

在AndroidManifest.xml中注册

 	    <service
            android:name=".aidl.BookManagerService"
            android:process=":BookManagerService">
        </service>

创建AidlActivity,和BookManagerService建立连接。

package com.example.test.aidl;

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

import com.example.test.R;

import java.util.List;

public class AidlActivity extends AppCompatActivity {

    private static final String TAG = "AidlActivity";

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            IBookManager iBookManager = IBookManager.Stub.asInterface(service);
            try {
                List<Book> bookList = iBookManager.getBookList();
                for (int i = 0; i < bookList.size(); i++) {
                    Book book = bookList.get(i);
                    Log.e(TAG, "Book: bookName ————"+book.getBookName() +"|||  bookId ————" +book.getBookId());
                }
            } catch (RemoteException e) {

            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

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

        Intent intent = new Intent(this,BookManagerService.class);
        bindService(intent,mServiceConnection, Context.BIND_AUTO_CREATE);
    }

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

运行程序,查看控制台数据。
在这里插入图片描述
在这里只调用了getBookList()方法,尝试调用一下addBook()方法。修改如下:

 private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            IBookManager iBookManager = IBookManager.Stub.asInterface(service);
            try {
                //添加一本书籍
                iBookManager.addBook(new Book(5,"三打白骨精"));
                
                List<Book> bookList = iBookManager.getBookList();
                
                for (int i = 0; i < bookList.size(); i++) {
                    Book book = bookList.get(i);
                    Log.e(TAG, "Book: bookName ————"+book.getBookName() +"|||  bookId ————" +book.getBookId());
                }
            } catch (RemoteException e) {

            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

重新运行,发现数据已经添加上去了。
在这里插入图片描述下面我们来模拟一下每当有新的图书添加进来就通知用户。首先需要提供一个AIDL接口,用户可以开启提醒和取消提醒。

首先创建IOnNewBookArrivedListener.aidl文件,并提供onNewBookArrived()方法

// IOnNewBookArrivedListener.aidl
package com.example.test.aidl;
import com.example.test.aidl.Book;
// Declare any non-default types here with import statements

interface IOnNewBookArrivedListener {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void onNewBookArrived(in Book book);
}

然后在原有的IBookManager.aidl中添加两个新方法

package com.example.test.aidl;
import com.example.test.aidl.Book;

interface IBookManager {
     List<Book> getBookList();
     void addBook(in Book book);
     void registerListener(IOnNewBookArrivedListener listener);
     void unregisterListener(IOnNewBookArrivedListener listener);
}

BookManagerService中也需要修改下,并在OnCreate()中启动了一个线程,每隔5秒添加一本新书到BookList中。

package com.example.test.aidl;

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

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Description:
 */

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

    private AtomicBoolean mAtomicBoolean = new AtomicBoolean(false);

    private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();
    private CopyOnWriteArrayList<IOnNewBookArrivedListener> mListenerList = new CopyOnWriteArrayList<>();

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

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

        @Override
        public void registerListener(IOnNewBookArrivedListener listener) throws RemoteException {
            if (!mListenerList.contains(listener)) {
                mListenerList.add(listener);
            }
            Log.e(TAG, "registerListener:   mListenerList大小"+mListenerList.size());
        }

        @Override
        public void unregisterListener(IOnNewBookArrivedListener listener) throws RemoteException {
            if (mListenerList.contains(listener)) {
                mListenerList.remove(listener);
            }else{
                Log.e(TAG, "找不到该listener  -----");
            }
            Log.e(TAG, "registerListener:   mListenerList大小"+mListenerList.size());
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();

        mBookList.add(new Book(1,"西游记"));
        mBookList.add(new Book(2,"红楼梦"));
        mBookList.add(new Book(3,"水浒传"));
        mBookList.add(new Book(4,"三国演义"));

        new Thread(new ServiceWorker()).start();
    }

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

    private void onNewBookArrived(Book book) throws RemoteException {
        mBookList.add(book);

        for (int i = 0; i < mListenerList.size(); i++) {
            IOnNewBookArrivedListener iOnNewBookArrivedListener = mListenerList.get(i);
            iOnNewBookArrivedListener.onNewBookArrived(book);
        }
    }

    private class ServiceWorker implements Runnable{

        @Override
        public void run() {
            //为真时一直执行
            while (!mAtomicBoolean.get()){

                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                int bookId = mBookList.size()+1;
                Book book = new Book(bookId,"火影忍者第"+bookId+"话");
                try {
                    onNewBookArrived(book);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
    }

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

然后AidlActivity中在连接BookManagerService时开启提醒,即注册,销毁的时候取消提醒,即取消注册。

package com.example.test.aidl;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import com.example.test.R;
import com.example.test.utils.Constants;

import java.util.List;

public class AidlActivity extends AppCompatActivity {

    private static final String TAG = "AidlActivity";
    private IBookManager mIBookManager;

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            IBookManager iBookManager = IBookManager.Stub.asInterface(service);
            try {
                mIBookManager = iBookManager;
                iBookManager.addBook(new Book(5,"三打白骨精"));

                List<Book> bookList = iBookManager.getBookList();

                for (int i = 0; i < bookList.size(); i++) {
                    Book book = bookList.get(i);
                    Log.e(TAG, "Book: bookName ————"+book.getBookName() +"|||  bookId ————" +book.getBookId());
                }
                //注册
                iBookManager.registerListener(mIOnNewBookArrivedListener);
            } catch (RemoteException e) {

            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case Constants.BOOKARRIVED:
                   Book book = (Book) msg.obj;
                    Log.e(TAG, "Book: bookName ————"+book.getBookName() +"|||  bookId ————" +book.getBookId());
                    break;
                    default:
                        super.handleMessage(msg);

                        break;
            }
        }
    };

    private IOnNewBookArrivedListener mIOnNewBookArrivedListener = new IOnNewBookArrivedListener.Stub() {
        @Override
        public void onNewBookArrived(Book book) throws RemoteException {
            mHandler.obtainMessage(Constants.BOOKARRIVED,book).sendToTarget();
        }
    };

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

        Intent intent = new Intent(this,BookManagerService.class);
        bindService(intent,mServiceConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        if (mIBookManager != null && mIBookManager.asBinder().isBinderAlive()) {
            try {
                //取消注册
                mIBookManager.unregisterListener(mIOnNewBookArrivedListener);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        unbindService(mServiceConnection);
        super.onDestroy();
    }
}

然后重新运行程序。可以看出来每隔5秒就会收到新书的消息。
在这里插入图片描述
那么问题来了,销毁AidlActivity 时取消提醒时并没有移除该listener
在这里插入图片描述
失败原因是因为Binder会把传递过来的对象重新转化并生成一个新的对象,所以会出现取消提醒失败的现象。那么解决办法是什么呢,那就需要用到了RemoteCallbackList。

RomoteCallbackList 是系统专门提供用于删除跨进程listener的接口
修改BookManagerService

private RemoteCallbackList<IOnNewBookArrivedListener> mListenerList = new RemoteCallbackList<>();

   @Override
        public void registerListener(IOnNewBookArrivedListener listener) throws RemoteException {

            mListenerList.register(listener);
            int size = mListenerList.beginBroadcast();
            Log.e(TAG, "registerListener:   mListenerList大小"+size);
            mListenerList.finishBroadcast();
        }

        @Override
        public void unregisterListener(IOnNewBookArrivedListener listener) throws RemoteException {

            mListenerList.unregister(listener);
            int size = mListenerList.beginBroadcast();
            Log.e(TAG, "unregisterListener:   mListenerList大小:"+size);
            mListenerList.finishBroadcast();

        }
 private void onNewBookArrived(Book book) throws RemoteException {
        mBookList.add(book);
        int size = mListenerList.beginBroadcast();
        for (int i = 0; i < size; i++) {
            IOnNewBookArrivedListener listener = mListenerList.getBroadcastItem(i);
            listener.onNewBookArrived(book);
        }
        mListenerList.finishBroadcast();
    }

然后重新运行程序,可以看到可以开启提醒和取消提醒了。
在这里插入图片描述RomoteCallbackList 的beginBroadcast()和finishBroadcast()必须配对使用。

权限验证

在AndroidManifest.xml中添加

<permission android:name="Permission.BookManagerService"
                android:protectionLevel="normal" />

<uses-permission android:name="Permission.BookManagerService"/>

BookManagerService中的onBInd()进行验证

   @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        int i = checkCallingOrSelfPermission("Permission.BookManagerService");
        Log.e(TAG, "onBind: i "+i);
        if (i == PackageManager.PERMISSION_DENIED) {
            return null;
        }
        return mBinder;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值