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());
      }
  }
}

 

 

posted @ 2020-05-28 17:21  LB笨小孩  阅读(751)  评论(0编辑  收藏  举报