• AIDL初识


    AIDL是一个缩写,全称是Android Interface Definition Language,也就是Android接口定义语言。

    AIDL的设计是为了实现进程间通信,如同两个进程的桥梁,传输一些特定规格的数据。

    Android中实现进程通信的几种方式:

    1、Activity (借助Intent调用其他APP的Activity实现跨进程通信)

    2、广播接收者(BroadcastReceiver)

    3、内容提供者(ContentProvider)

    4、AIDL(Android Interface definition language,Android接口定义语言)

    AIDL特殊的语法:

    文件类型:用AIDL书写的文件的后缀是 .aidl,而不是 .java。

    数据类型:

      默认支持的数据类型包括:

    • Java中的八种基本数据类型,包括 byte,short,int,long,float,double,boolean,char。
    • String 类型。
    • CharSequence类型。
    • List类型:List中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelable(下文关于这个会有详解)。List可以使用泛型。
    • Map类型:Map中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelable。Map是不支持泛型的。
    • 定向tag:AIDL中的定向 tag 表示了在跨进程通信中数据的流向,其中 in 表示数据只能由客户端流向服务端, out 表示数据只能由服务端流向客户端,而 inout 则表示数据可在服务端与客户端之间双向流通。

    两种AIDL文件:一类是用来定义parcelable对象,以供其他AIDL文件使用AIDL中非默认支持的数据类型的。一类是用来定义方法接口,以供系统使用来完成跨进程通信的。

    AIDL实现跨进程通信:

    1、使数据实现Parcelable接口

      客户端传入服务端的对象需要经过序列化操作,将数据转化为序列化流传到服务端,再由服务端进行反序列化获取数据。AIDL中实现序列化的方式是实现Parcelable接口。如果是默认支持数据类型则无需进行序列化操作。

      in的定向Tag方法为writeToParcel() ,out的定向Tag方法为 readFromParcel() 

    package com.lypeer.ipcclient;
    
    import android.os.Parcel;
    import android.os.Parcelable;
    
    /**
     * Book.java
     *
     * Created by lypeer on 2016/7/16.
     */
    public class Book implements Parcelable{
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getPrice() {
            return price;
        }
    
        public void setPrice(int price) {
            this.price = price;
        }
    
        private String name;
        private int price;
        public Book(){}
    
        public Book(Parcel in) {
            name = in.readString();
            price = in.readInt();
        }
    
        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];
            }
        };
    
        @Override
        public int describeContents() {
            return 0;
        }
    
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(name);
            dest.writeInt(price);
        }
    
        /**
         * 参数是一个Parcel,用它来存储与传输数据
         * @param dest
         */
        public void readFromParcel(Parcel dest) {
            //注意,此处的读值顺序应当是和writeToParcel()方法中一致的
            name = dest.readString();
            price = dest.readInt();
        }
    
        //方便打印数据
        @Override
        public String toString() {
            return "name : " + name + " , price : " + price;
        }
    }

    2、新建AIDL文件

    // Book.aidl
    //第一类AIDL文件
    //这个文件的作用是引入了一个序列化对象 Book 供其他的AIDL文件使用
    //注意:Book.aidl与Book.java的包名应当是一样的
    package com.lypeer.ipcclient;
    
    //注意parcelable是小写
    parcelable Book;
    // BookManager.aidl
    //第二类AIDL文件
    //作用是定义方法接口
    package com.lypeer.ipcclient;
    //导入所需要使用的非默认支持数据类型的包
    import com.lypeer.ipcclient.Book;
    
    interface BookManager {
    
        //所有的返回值前都不需要加任何东西,不管是什么数据类型
        List<Book> getBooks();
    
        //传参时除了Java基本类型以及String,CharSequence之外的类型
        //都需要在前面加上定向tag,具体加什么量需而定
        void addBook(in Book book);
    }

      Book.aidl与Book.java的包名应当是一样的。这似乎理所当然的意味着这两个文件应当是在同一个包里面的,然而在 Android Studio如果这样做的话,系统根本就找不到 Book.java 文件,两种解决方法如下:

    (1)修改 build.gradle 文件:在 android{} 中间加上下面的内容:

    sourceSets {
     main {
         java.srcDirs = ['src/main/java', 'src/main/aidl']
     }
    }

    (2)把 java 文件放到 java 包下去:把 Book.java 放到 java 包里任意一个包下,保持其包名不变,与 Book.aidl 一致。

    3、复制相关文件

      将在一端的AIDL文件写完后,复制到另一端。(一般情况是服务端写好复制到客户端)

    4、编写服务端代码

    /**
     * 服务端的AIDLService.java
     * <p/>
     * Created by lypeer on 2016/7/17.
     */
    public class AIDLService extends Service {
    
        public final String TAG = this.getClass().getSimpleName();
    
        //包含Book对象的list
        private List<Book> mBooks = new ArrayList<>();
    
        //由AIDL文件生成的BookManager
        private final BookManager.Stub mBookManager = new BookManager.Stub() {
            @Override
            public List<Book> getBooks() throws RemoteException {
                synchronized (this) {
                    Log.e(TAG, "invoking getBooks() method , now the list is : " + mBooks.toString());
                    if (mBooks != null) {
                        return mBooks;
                    }
                    return new ArrayList<>();
                }
            }
    
    
            @Override
            public void addBook(Book book) throws RemoteException {
                synchronized (this) {
                    if (mBooks == null) {
                        mBooks = new ArrayList<>();
                    }
                    if (book == null) {
                        Log.e(TAG, "Book is null in In");
                        book = new Book();
                    }
                    //尝试修改book的参数,主要是为了观察其到客户端的反馈
                    book.setPrice(2333);
                    if (!mBooks.contains(book)) {
                        mBooks.add(book);
                    }
                    //打印mBooks列表,观察客户端传过来的值
                    Log.e(TAG, "invoking addBooks() method , now the list is : " + mBooks.toString());
                }
            }
        };
    
        @Override
        public void onCreate() {
            super.onCreate();
            Book book = new Book();
            book.setName("Android开发艺术探索");
            book.setPrice(28);
            mBooks.add(book);   
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            Log.e(getClass().getSimpleName(), String.format("on bind,intent = %s", intent.toString()));
            return mBookManager;
        }
    }

    代码分为三个部分:

      第一块是初始化。在 onCreate() 方法里面我进行了一些数据的初始化操作。
      第二块是重写 BookManager.Stub 中的方法。在这里面提供AIDL里面定义的方法接口的具体实现逻辑。
      第三块是重写 onBind() 方法。在里面返回写好的 BookManager.Stub 。
    在 AndroidManifest 文件里面注册这个我们写好的 Service。(必须)
    <service
        android:name=".service.AIDLService"
        android:exported="true">
            <intent-filter>
                <action android:name="com.lypeer.aidl"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
    </service>

    5、编写客户端代码

    public class AIDLActivity extends AppCompatActivity {
    
        //由AIDL文件生成的Java类
        private BookManager mBookManager = null;
    
        //标志当前与服务端连接状况的布尔值,false为未连接,true为连接中
        private boolean mBound = false;
    
        //包含Book对象的list
        private List<Book> mBooks;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_aidl);
        }
    
        /**
         * 按钮的点击事件,点击之后调用服务端的addBookIn方法
         *
         * @param view
         */
        public void addBook(View view) {
            //如果与服务端的连接处于未连接状态,则尝试连接
            if (!mBound) {
                attemptToBindService();
                Toast.makeText(this, "当前与服务端处于未连接状态,正在尝试重连,请稍后再试", Toast.LENGTH_SHORT).show();
                return;
            }
            if (mBookManager == null) return;
    
            Book book = new Book();
            book.setName("APP研发录In");
            book.setPrice(30);
            try {
                mBookManager.addBook(book);
                Log.e(getLocalClassName(), book.toString());
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 尝试与服务端建立连接
         */
        private void attemptToBindService() {
            Intent intent = new Intent();
            intent.setAction("com.lypeer.aidl");
            intent.setPackage("com.lypeer.ipcserver");
            bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
        }
    
        @Override
        protected void onStart() {
            super.onStart();
            if (!mBound) {
                attemptToBindService();
            }
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            if (mBound) {
                unbindService(mServiceConnection);
                mBound = false;
            }
        }
    
        private ServiceConnection mServiceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.e(getLocalClassName(), "service connected");
                mBookManager = BookManager.Stub.asInterface(service);
                mBound = true;
    
                if (mBookManager != null) {
                    try {
                        mBooks = mBookManager.getBooks();
                        Log.e(getLocalClassName(), mBooks.toString());
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                Log.e(getLocalClassName(), "service disconnected");
                mBound = false;
            }
        };
    }

    参考文章:http://www.jianshu.com/p/a8e43ad5d7d2

  • 相关阅读:
    《影响力》为你剖析营销的魅力 伍卓钧
    教你如何掌控别人 伍卓钧
    针对面向对象接口最诡异的解读 伍卓钧
    2011年终总结 伍卓钧
    打造阅读Linux源代码利器 伍卓钧
    系统运维的那些事文件权限 伍卓钧
    风扇控制系统最终版 伍卓钧
    码农小手册1 伍卓钧
    码农充电站进程与线程 伍卓钧
    面霸不容易且面且珍惜 伍卓钧
  • 原文地址:https://www.cnblogs.com/yl-saber/p/7360537.html
Copyright © 2020-2023  润新知