zoukankan      html  css  js  c++  java
  • AIDL详解

    AIDL详解

    1、简介:

    AIDL是Android中IPC(Inter-Process Communication)方式中的一种,AIDL是Android Interface definition language的缩写。

    其主要作用是用于进程间的通讯。

    在Android系统中,每个进程都运行在一块独立的内存中,在其中完成自己的各项活动,与其他进程都分隔开来。可是有时候我们又有应用间进行互动的需求,比较传递数据或者任务委托等,AIDL就是为了满足这种需求而诞生的。通过AIDL,可以在一个进程中获取另一个进程的数据和调用其暴露出来的方法,从而满足进程间通信的需求。

    2、特性:

    • 支持的数据类型: 八种基本数据类型:byte、char、short、int、long、float、double、boolean String,CharSequence 实现了Parcelable接口的数据类型 List 类型。List承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象 Map类型。Map承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象

    • AIDL文件可以分为两类。一类用来声明实现了Parcelable接口的数据类型,以供其他AIDL文件使用那些非默认支持的数据类型。还有一类是用来定义接口方法,声明要暴露哪些接口给客户端调用,定向Tag就是用来标注这些方法的参数值。

    • 定向Tag。定向Tag表示在跨进程通信中数据的流向,用于标注方法的参数值,分为 in、out、inout 三种。其中 in 表示数据只能由客户端流向服务端, out 表示数据只能由服务端流向客户端,而 inout 则表示数据可在服务端与客户端之间双向流通。此外,如果AIDL方法接口的参数值类型是:基本数据类型、String、CharSequence或者其他AIDL文件定义的方法接口,那么这些参数值的定向 Tag 默认是且只能是 in,所以除了这些类型外,其他参数值都需要明确标注使用哪种定向Tag。

    • 明确导包。在AIDL文件中需要明确标明引用到的数据类型所在的包名,即使两个文件处在同个包名下。

    3、实例:

    服务端:

    完整服务端在 '.'(main)目录下的文件结构:

    .
    ├── aidl
    │   └── com
    │       └── example
    │           └── myaidl
    │               ├── Book.aidl
    │               └── BookController.aidl
    ├── AndroidManifest.xml
    ├── java
    │   └── com
    │       └── example
    │           └── myaidl
    │               ├── AIDLService.java
    │               ├── Book.java
    │               └── MainActivity.java

    右键之后的New选项中有一个AIDL,选中创建Book.aidl,会出现如下目录文件:

    .
    ├── aidl
    │   └── com
    │       └── example
    │           └── myaidl
    │               ├── Book.aidl

    Book.aidl

    package com.example.myaidl;
    parcelable Book;

    下来定义Book类,注意Book类的包名必须与Book.aidl包名一样,但是不可与Book.aidl在同一个目录下。

    Book.java

    package com.example.myaidl;

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

    public class Book implements Parcelable {
       private String name;

       public Book(String name) {
           this.name = name;
      }

       public String getName() {
           return name;
      }

       public void setName(String name) {
           this.name = name;
      }

       @Override
       public String toString() {
           return "book name:" + name;
      }

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

       @Override
       public void writeToParcel(Parcel dest, int flags) {
           dest.writeString(this.name);
      }

       public void readFromParcel(Parcel dest) {
           name = dest.readString();
      }

       protected Book(Parcel in) {
           this.name = in.readString();
      }

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

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

    接下来便是要定义服务端暴露给客户端的接口了(获取书籍列表,添加书籍)

    在同样的目录定义aidl文件BookController.aidl

    package com.example.myaidl;
       import com.example.myaidl.Book;

       interface BookController {
       List<Book> getBookList();

       void addBookInOut(inout Book book);
    }

    注意要把包手动导进来。然后将项目clean一下

    创建service

    package com.example.myaidl;

    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.os.RemoteException;
    import android.util.Log;

    import androidx.annotation.Nullable;

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

    public class AIDLService extends Service {
       private final String TAG = "AIDLserver";

       private volatile List<Book> mBookList;

       public AIDLService(){

      }

       @Override
       public void onCreate() {
           super.onCreate();
           mBookList = new ArrayList<>();
           initData();
      }

       private void initData(){
           Book book1 = new Book("C++");
           Book book2 = new Book("Java");
           Book book3 = new Book("C#");
           Book book4 = new Book("PHP");
           Book book5 = new Book("JS");
           Book book6 = new Book("GO");
           mBookList.add(book1);
           mBookList.add(book2);
           mBookList.add(book3);
           mBookList.add(book4);
           mBookList.add(book5);
           mBookList.add(book6);
      }

       private final BookController.Stub mStub = new BookController.Stub() {
           @Override
           public List<Book> getBookList() throws RemoteException {
               Log.d("aidlBooklist", "=========================");
               for (Book bk: mBookList){
                   Log.d("aidlBooklist", bk.getName());
              }
               Log.d("aidlBooklist", "=========================");
               return mBookList;
          }

           @Override
           public void addBookInOut(Book book) throws RemoteException {
               synchronized (this){
                   if (book != null) {
                       book.setName(book.getName());
                       mBookList.add(book);
                       Log.d("aidlBooklist", "=========================");
                       for (Book bk: mBookList){
                           Log.d("aidlBooklist", bk.getName());
                      }
                       Log.d("aidlBooklist", "=========================");
                       Log.e(TAG, "接收到书名:"+book.getName());
                  } else {
                       Log.e(TAG, "接收到了一个空对象 InOut");
                  }
              }
          }
      };

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

    MainActivity.java

    import androidx.appcompat.app.AppCompatActivity;

    import android.content.Intent;
    import android.os.Bundle;

    public class MainActivity extends AppCompatActivity {
    private Intent mIntent;

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

           mIntent = new Intent(this,AIDLService.class);
           startService(mIntent);
      }

       @Override
       protected void onDestroy() {
           super.onDestroy();
          // stopService(mIntent);
      }
    }

    AndroidManifest.xml

    <service android:name=".AIDLService"
       android:enabled="true"
       android:exported="true">
       <intent-filter>
       <action android:name="com.example.myaidl.action"/>
       <category android:name="android.intent.category.DEFAULT"/>
       </intent-filter>
    </service>

    onBind方法返回的是BookManager.Stub对象,实现里面的两个方法,客户端拿到这个对象后就可以与服务端通讯了。

    客户端:

    创建新的项目

    .
    ├── aidl
    │   └── com
    │       └── example
    │           └── myaidl
    │               ├── Book.aidl
    │               └── BookController.aidl
    ├── AndroidManifest.xml
    ├── java
    │   └── com
    │       └── example
    │           ├── myaidl
    │           │   └── Book.java
    │           └── myclient
    │               └── MainActivity.java

    将aidl文件与Book.class拷贝到客户端的工程,注意他们的目录需要与服务端的一样,也就是说aidl与Book.class包名要与服务端的一样。

    连接服务端:MainActivity

    package com.example.myclient;

    import androidx.appcompat.app.AppCompatActivity;

    import android.content.ComponentName;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.Bundle;
    import android.os.IBinder;
    import android.os.RemoteException;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;

    import com.example.myaidl.Book;
    import com.example.myaidl.BookController;

    import java.util.List;

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
       private final String TAG = "MyClient";

       private BookController mBookController;

       private boolean connected;

       private List<Book> mBookList;

       private ServiceConnection mServiceConnection = new ServiceConnection() {
           @Override
           public void onServiceConnected(ComponentName name, IBinder service) {
               mBookController = BookController.Stub.asInterface(service);
               connected = true;
          }

           @Override
           public void onServiceDisconnected(ComponentName name) {
               connected = false;
          }
      };
       private Button mGetBookList;
       private Button mAddBook_inOut;
       private Button mStopConnect;
       private EditText mEditText;

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

           mGetBookList = findViewById(R.id.btn_getBookList);
           mGetBookList.setOnClickListener(this);

           mAddBook_inOut = findViewById(R.id.btn_addBook_inOut);
           mAddBook_inOut.setOnClickListener(this);

           mStopConnect = findViewById(R.id.btn_stopConnect);
           mStopConnect.setOnClickListener(this);

           mEditText = findViewById(R.id.getbook);
               bindServace();
    }

    @Override
    public void onClick(View v) {
       int i = v.getId();
       switch (i){
           case R.id.btn_getBookList:
               if (connected){
                   try {
                       mBookList = mBookController.getBookList();
                       for (Book bk: mBookList){
                           Log.d("ClientBooklist", bk.getName());
                      }
                  } catch (RemoteException e) {
                       e.printStackTrace();
                  }
                   log();
              }
               break;

           case R.id.btn_addBook_inOut:
               if (connected){
                   String book_name = mEditText.getText().toString().trim();
                   Book bk = new Book(book_name);
                   try {
                       mBookController.addBookInOut(bk);
                       Log.d(TAG, "添加:"+bk.getName());
                       Log.d(TAG, "书名: "+bk.getName());
                  } catch (RemoteException e) {
                       e.printStackTrace();
                  }
              }
               break;

           case R.id.btn_stopConnect:
               if (connected){
                   unbindService(mServiceConnection);
              }
               break;
      }
    }

       @Override
       protected void onDestroy() {
           super.onDestroy();
       //       if (connected){
       //           unbindService(mServiceConnection);
       //       }
          }
       private void bindServace(){
       Intent intent = new Intent();
       intent.setPackage("com.example.myaidl");
       intent.setAction("com.example.myaidl.action");
       bindService(intent,mServiceConnection,BIND_AUTO_CREATE);
      }

       private void log(){
           for (Book bk : mBookList){
               Log.d(TAG, bk.toString());
          }
      }
    }

     

     

  • 相关阅读:
    客户端组建调用
    串口开发
    C/C++,系统知识考点
    API进程线程函数
    做WEB2.0网站可以参考的十九条规则
    javascript中动态添加事件!!
    常用正则表达式收集!
    CuteChat for Community Server 2.0 beta 3!
    发现一个下载.Text Skin 的好网站.
    如何控制Linux终端打印字符颜色和位置
  • 原文地址:https://www.cnblogs.com/littleboy123/p/12982195.html
Copyright © 2011-2022 走看看