亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Android  AIDL——進(jìn)程通信機(jī)制詳解

 更新時(shí)間:2016年10月31日 09:15:40   作者:small_123  
這篇文章主要介紹了Android AIDL——進(jìn)程通信機(jī)制詳解的相關(guān)資料,并附簡單實(shí)例,和實(shí)現(xiàn)效果圖,需要的朋友可以參考下

Android  AIDL, Android進(jìn)程機(jī)制通信機(jī)制,這里就整理下AIDL 的知識(shí),幫助大家學(xué)習(xí)理解此部分知識(shí)!

什么是 AIDL

AIDL 全稱 Android Interface Definition Language,即 安卓接口描述語言。聽起來很深?yuàn)W,其實(shí)它的本質(zhì)就是生成進(jìn)程間通信接口的輔助工具。它的存在形式是一種 .aidl 文件,開發(fā)者需要做的就是在該文件中定義進(jìn)程間通信的接口,編譯的時(shí)候 IDE 就會(huì)根據(jù)我們的 .aidl 接口文件生成可供項(xiàng)目使用的 .java 文件,這和我們說的“語法糖”有些類似。

AIDL 的語法就是 java 的語法,就是導(dǎo)包上有點(diǎn)細(xì)微差別。java 中如果兩個(gè)類在相同的包中,是不需要進(jìn)行導(dǎo)包操作的,但是在 AIDL 中,則必須進(jìn)行導(dǎo)包聲明。

 AIDL 詳解

構(gòu)想一個(gè)場景:我們有一個(gè)圖書管理系統(tǒng),這個(gè)系統(tǒng)的通過 CS 模式來實(shí)現(xiàn)。具體的管理功能由服務(wù)端進(jìn)程來實(shí)現(xiàn),客戶端只需要調(diào)用相應(yīng)的接口就可以。

那么首先定義這個(gè)管理系統(tǒng)的 ADIL 接口。

我們在 /rc 新建 aidl 包,包中有三個(gè)文件 Book.java 、Book.aidl、IBookManager.aidl 三個(gè)文件。

package com.example.aidl book

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

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

 ...
}

package com.example.aidl;

Parcelable Book;

package com.example.aidl;

import com.example.aidl.Book;

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

下面對(duì)這三個(gè)文件分別進(jìn)行說明:

Book.java 是我們定義的實(shí)體類,它實(shí)現(xiàn)了 Parcelable 接口,這樣 Book 類才能在進(jìn)程間傳輸。
Book.aidl 是這個(gè)實(shí)體類在 AIDL 中的聲明。
IBookManager 是服務(wù)端和客戶端通信的接口。(注意,在 AIDL 接口中除基本類型外,參數(shù)前須加方向,in 表示輸入型參數(shù),out 表示輸出型參數(shù),inout 表示輸入輸出型參數(shù))

編譯器編譯后,android studio 為我們的項(xiàng)目自動(dòng)生成了一個(gè) .java 文件,這個(gè)文件包含三個(gè)類,這三個(gè)類分別是 IBookManager, Stub 和 Proxy,這三個(gè)類都是靜態(tài)類型,我們完全可以把他們分開來,三個(gè)類定義如下:

IBookManager



public interface IBookManager extends android.os.IInterface {

  public void addBook(net.bingyan.library.Book book) throws android.os.RemoteException;

  public java.util.List<net.bingyan.library.Book> getBookList() throws android.os.RemoteException;
}

Stub



public static abstract class Stub extends android.os.Binder implements net.bingyan.library.IBookManager {
    private static final java.lang.String DESCRIPTOR = "net.bingyan.library.IBookManager";

    static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    /**
     * Construct the stub at attach it to the interface.
     */
    public Stub() {
      this.attachInterface(this, DESCRIPTOR);
    }

    /**
     * Cast an IBinder object into an net.bingyan.library.IBookManager interface,
     * generating a proxy if needed. http://www.manongjc.com/article/1501.html
     */
    public static net.bingyan.library.IBookManager asInterface(android.os.IBinder obj) {
      if ((obj == null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin != null) && (iin instanceof net.bingyan.library.IBookManager))) {
        return ((net.bingyan.library.IBookManager) iin);
      }
      return new net.bingyan.library.IBookManager.Stub.Proxy(obj);
    }

    @Override
    public android.os.IBinder asBinder() {
      return this;
    }

    @Override
    public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
      switch (code) {
        case INTERFACE_TRANSACTION: {
          reply.writeString(DESCRIPTOR);
          return true;
        }
        case TRANSACTION_addBook: {
          data.enforceInterface(DESCRIPTOR);
          net.bingyan.library.Book _arg0;
          if ((0 != data.readInt())) {
            _arg0 = net.bingyan.library.Book.CREATOR.createFromParcel(data);
          } else {
            _arg0 = null;
          }
          this.addBook(_arg0);
          reply.writeNoException();
          return true;
        }
        case TRANSACTION_getBookList: {
          data.enforceInterface(DESCRIPTOR);
          java.util.List<net.bingyan.library.Book> _result = this.getBookList();
          reply.writeNoException();
          reply.writeTypedList(_result);
          return true;
        }
      }
      return super.onTransact(code, data, reply, flags);
    }
}

Proxy



private static class Proxy implements net.bingyan.library.IBookManager {
      private android.os.IBinder mRemote;

      Proxy(android.os.IBinder remote) {
        mRemote = remote;
      }

      @Override
      public android.os.IBinder asBinder() {
        return mRemote;
      }

      public java.lang.String getInterfaceDescriptor() {
        return DESCRIPTOR;
      }

      /**
       * Demonstrates some basic types that you can use as parameters
       * and return values in AIDL.  http://www.manongjc.com/article/1500.html
       */
      @Override
      public void addBook(net.bingyan.library.Book book) throws android.os.RemoteException {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          if ((book != null)) {
            _data.writeInt(1);
            book.writeToParcel(_data, 0);
          } else {
            _data.writeInt(0);
          }
          mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
          _reply.readException();
        } finally {
          _reply.recycle();
          _data.recycle();
        }
      }

      @Override
      public java.util.List<net.bingyan.library.Book> getBookList() throws android.os.RemoteException {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        java.util.List<net.bingyan.library.Book> _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
          _reply.readException();
          _result = _reply.createTypedArrayList(net.bingyan.library.Book.CREATOR);
        } finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
    }

對(duì)生成的這三個(gè)類的說明如下:

  1. IBookManager 這個(gè)類是我們定義的接口,android studio 給它添加了一個(gè)父類,讓它繼承自 android.os.interface 這個(gè)接口,這個(gè)接口只有一個(gè)方法 IBinder asBinder(),這樣 IBookManager 中就有三個(gè)帶實(shí)現(xiàn)的方法了,它是服務(wù)端進(jìn)程和客戶端進(jìn)程通信的窗口。
  2. Stub 是個(gè)抽象類,這個(gè)類繼承自 android.os.Binder 類,并且實(shí)現(xiàn)的了 IBookManager 這個(gè)接口。在 Stub 中,已經(jīng)實(shí)現(xiàn)了 asBinder() 這個(gè)接口方法,還有兩個(gè)是我們定義的 AIDL 接口方法留給繼承它的子類去實(shí)現(xiàn)。它用在服務(wù)端,因此服務(wù)端需要實(shí)現(xiàn)這兩個(gè)方法。
  3. Proxy 顧名思義是一個(gè)代理類,它是服務(wù)端在客戶端的一個(gè)代理,它也實(shí)現(xiàn)了 IBookManager接口,并且實(shí)現(xiàn)了 IBookManager 中的所有方法。它用在客戶端,是服務(wù)端在客戶端的代理?,F(xiàn)在我們對(duì)這三個(gè)類逐個(gè)分析:
  4. IBookManager 這個(gè)類沒什么好說的,它只是簡單繼承了 asInterface 這個(gè)接口,作用就是將 IBookManager 轉(zhuǎn)換成 IBinder。
  5. Proxy 這個(gè)類上面已經(jīng)提到過了,它就是進(jìn)程間通信機(jī)制的一個(gè)封裝類,他的內(nèi)部實(shí)現(xiàn)機(jī)制就是 Binder,通過構(gòu)造方法我們也容易看出來。它的構(gòu)造方法接受一個(gè) IBinder 類型的參數(shù),參數(shù)名為 remote,顯然,它代表著服務(wù)端。我們看看這個(gè)類中的方法 addBook() 和 getBookList():
@Override
public void addBook(net.bingyan.library.Book book) throws android.os.RemoteException {
   android.os.Parcel _data = android.os.Parcel.obtain();
   android.os.Parcel _reply = android.os.Parcel.obtain();
   try {
      _data.writeInterfaceToken(DESCRIPTOR)
      if ((book != null)) {
        _data.writeInt(1);
        book.writeToParcel(_data, 0);
      } else {
        _data.writeInt(0);
      }
      mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
      _reply.readException();
    } finally {
      _reply.recycle();
      _data.recycle();
    }
}
@Override /* http://www.manongjc.com/article/1547.html */
public java.util.List<net.bingyan.library.Book> getBookList() throws android.os.RemoteException {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    java.util.List<net.bingyan.library.Book> _result;
    try {
       _data.writeInterfaceToken(DESCRIPTOR);
       mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
       _reply.readException();
       _result = _reply.createTypedArrayList(net.bingyan.library.Book.CREATOR);
    } finally {
      _reply.recycle();
      _data.recycle();
    }
    return _result;
}

它們是編譯器自動(dòng)實(shí)現(xiàn)的,這兩個(gè)方法有很多類似之處,可以現(xiàn)在這里透露下:這兩個(gè)方法就是客戶端進(jìn)程調(diào)用服務(wù)端進(jìn)程的窗口。在這兩個(gè)方法的開始,它們都定義了兩個(gè) Parcel(中文譯名:包裹)對(duì)象。Parcel 這個(gè)類我們看上去很眼熟,是的,Book 類中的 writeToParcel() 和 CREATOR中的 createFromParcel() 的參數(shù)就是 Parcel 類型的,關(guān)于這個(gè)類文檔中解釋如下:

Container for a message (data and object references) that can be sent through an IBinder. A Parcel can contain both flattened data that will be unflattened on the other side of the IPC (using the various methods here for writing specific types, or the general {@link Parcelable} interface), and references to live {@link IBinder} objects that will result in the other side receiving a proxy IBinder connected with the original IBinder in the Parcel.

翻譯一下:Proxy 是一個(gè)可以通過 IBinder 進(jìn)行消息傳遞的一個(gè)容器。一個(gè) Parcel 可以包含可序列化的數(shù)據(jù),這些數(shù)據(jù)會(huì)在 IPC 的另一端被反序列化;它也可以包含指向 IBinder 對(duì)象的引用,這會(huì)使得另一端接收到一個(gè) IBinder 類型的代理對(duì)象,這個(gè)代理對(duì)象連接著 Parcel 中的原始 IBinder 對(duì)象。

下面用圖來直觀的說明:

Android 進(jìn)程通信機(jī)制之 AIDL

如圖,我們可以很直觀的看到服務(wù)端以 Parcel 作為數(shù)據(jù)包裹依靠 Binder 和客戶端進(jìn)行通信。數(shù)據(jù)包裹就是序列化之后的對(duì)象。

如上所述,這兩個(gè)方法都定義了兩個(gè) Parcel 對(duì)象,分別叫做 _data 和 _reply,形象的來說,從客戶端的角度來看,_data 就是客戶端發(fā)送給服務(wù)端的數(shù)據(jù)包裹,_reply 服務(wù)端發(fā)送給客戶端的數(shù)據(jù)包裹。

之后便開始用這兩個(gè)對(duì)象來和服務(wù)端進(jìn)行通信了,我們能夠觀察到,兩個(gè)方法中都有這么個(gè)方法調(diào)用 mRemote.transact(),它有四個(gè)參數(shù),第一個(gè)參數(shù)的意義我們后面再講,第二個(gè)參數(shù) _data 負(fù)責(zé)向服務(wù)端發(fā)送數(shù)據(jù)包裹比如接口方法的參數(shù),第三個(gè)參數(shù) _reply 負(fù)責(zé)從服務(wù)端接收數(shù)據(jù)包裹比如接口方法的返回值。這行代碼只有一句簡單的方法調(diào)用,但是卻是 AIDL 通信的最核心部分,它其實(shí)進(jìn)行了一次遠(yuǎn)程方法調(diào)用(客戶端通過本地代理 Proxy 暴露的接口方法調(diào)用服務(wù)端 Stub 同名方法),所以能想到它是一個(gè)耗時(shí)操作。

在我們的例子中:

1.void addBook(Book book) 需要借助 _data 向服務(wù)端發(fā)送參數(shù) Book:book,發(fā)送的方式就是把 Book 通過其實(shí)現(xiàn)的 writeToParcel(Parcel out) 方法打包至 _data 中,正如你能想到的,_data 其實(shí)就是參數(shù) out,還記得 Book 中的這個(gè)方法的實(shí)現(xiàn)嗎? 我們是將 Book 的字段一個(gè)個(gè)打包至 Parcel 中的。

2.List<Book> getBookList() 需要借助 _reply 從服務(wù)端接收返回值 List<Book>:books,方法中的做法是將 Book 中的 CREATOR 這個(gè)靜態(tài)字段作為參數(shù)傳入 _reply 的 createTypedArrayList() 方法中,還記得 Book 中的 CREATOR 嗎?當(dāng)時(shí)你是不是好奇這個(gè)靜態(tài)字段應(yīng)該怎么用呢?現(xiàn)在一切明了了,我們需要靠這個(gè)對(duì)象(便于理解我們可以叫它”反序列化器“)來對(duì)服務(wù)端的數(shù)據(jù)反序列化從而重新生成可序列化的對(duì)象或者對(duì)象數(shù)組。很明顯 CREATOR 借助 _reply 生成了 List<Book>:books。

當(dāng)然這兩個(gè)方法中的 _data 和 _reply 不僅傳遞了對(duì)象,還傳遞了一些校驗(yàn)信息,這個(gè)我們可以不必深究,但應(yīng)注意的是,Parcel 打包順序和解包順序要嚴(yán)格對(duì)應(yīng)。例如,第一個(gè)打包的是 int:i,那么第一解包的也應(yīng)該是這個(gè)整型值。也即打包時(shí)第一次調(diào)用的如果是 Parcel.writeInt(int),解包時(shí)第一次調(diào)用的應(yīng)該是 Parcel.readInt()。

到此,客戶端的 Proxy 講解完了,下面我們看看服務(wù)端的 Stub。

Stub 中實(shí)現(xiàn)了 IBookManager 的其中一個(gè)方法,這個(gè)很簡單,就是簡單的將自身返回,因?yàn)?Stub 本身就繼承自 Binder,而 Binder 繼承自 IBinder,所以沒有任何問題。你會(huì)問:還有兩個(gè)方法沒實(shí)現(xiàn)呢?這兩個(gè)方法就是我們定義的接口方法,它們留給服務(wù)端進(jìn)程去實(shí)現(xiàn),也就是說,到時(shí)候我們在服務(wù)端進(jìn)程中需要定義一個(gè) Stub 的實(shí)現(xiàn)者。下面對(duì) Stub 中的兩個(gè)重要方法進(jìn)行分析:

IBookManager asInterface(IBinder obj)

public static net.bingyan.library.IBookManager asInterface(android.os.IBinder obj) {
      if ((obj == null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin != null) && (iin instanceof net.bingyan.library.IBookManager))) {
        return ((net.bingyan.library.IBookManager) iin);
      }
      return new net.bingyan.library.IBookManager.Stub.Proxy(obj);
    }

這個(gè)方法的作用是將 Stub 類轉(zhuǎn)換成 IBookManager 這個(gè)接口,方法中有個(gè)判斷:如果我們的服務(wù)端進(jìn)程和客戶端進(jìn)程是同一進(jìn)程,那么就直接將 Stub 類通過類型轉(zhuǎn)換轉(zhuǎn)成 IBookManager;如果不是同一進(jìn)程,那么就通過代理類 Proxy 將 Stub 轉(zhuǎn)換成 IBookManager。為什么這么做,我們知道如果服務(wù)端進(jìn)程和客戶端進(jìn)程不是同一進(jìn)程,那么它們的內(nèi)存就不能共享,就不能通過一般的方式進(jìn)行通信,但是我們?nèi)绻约喝?shí)現(xiàn)進(jìn)程間通信方式,對(duì)于普通開發(fā)者來說成本太大,因此編譯器幫我們生成了一個(gè)封裝了了進(jìn)程間通信的工具,也就是這個(gè) Proxy,這個(gè)類對(duì)底層的進(jìn)程通信機(jī)制進(jìn)行了封裝只同時(shí)暴露出接口方法,客戶端只需要調(diào)用這兩個(gè)方法實(shí)現(xiàn)進(jìn)程間通信(其實(shí)就是方法的遠(yuǎn)程調(diào)用)而不需要了解其中的細(xì)節(jié)。

有了這個(gè)方法,我們在客戶端可以借助其將一個(gè) IBinder 類型的變量轉(zhuǎn)換成我們定義的接口 IBookManager,它的使用場景我們會(huì)在后面的實(shí)例中進(jìn)行講解。

onTransact(int code, Parcel data, Parcel reply, int flags)

@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
      switch (code) {
        case INTERFACE_TRANSACTION: {
          reply.writeString(DESCRIPTOR);
          return true;
        }
        case TRANSACTION_addBook: {
          data.enforceInterface(DESCRIPTOR);
          net.bingyan.library.Book _arg0;
          if ((0 != data.readInt())) {
            _arg0 = net.bingyan.library.Book.CREATOR.createFromParcel(data);
          } else {
            _arg0 = null;
          }
          this.addBook(_arg0);
          reply.writeNoException();
          return true; /* http://www.manongjc.com/article/1499.html */
        }
        case TRANSACTION_getBookList: {
          data.enforceInterface(DESCRIPTOR);
          java.util.List<net.bingyan.library.Book> _result = this.getBookList();
          reply.writeNoException();
          reply.writeTypedList(_result);
          return true;
        }
      }
      return super.onTransact(code, data, reply, flags);
}

這個(gè)方法我們是不是也很熟悉呢?我們在 Proxy 中也看到一個(gè)類似得方法 transact(int, Parcel, Parcel, int),它們的參數(shù)一樣,而且它們都是 Binder 中的方法,那么它們有什么聯(lián)系呢?

前面說了,transact() 執(zhí)行了一個(gè)遠(yuǎn)程調(diào)用,如果說 transact() 是遠(yuǎn)程調(diào)用的發(fā)起,那么 onTransact() 就是遠(yuǎn)程調(diào)用的響應(yīng)。真實(shí)過程是客戶端發(fā)器遠(yuǎn)程方法調(diào)用,android 系統(tǒng)通過底層代碼對(duì)這個(gè)調(diào)用進(jìn)行響應(yīng)和處理,之后回調(diào)服務(wù)端的 onTransact() 方法,從數(shù)據(jù)包裹中取出方法參數(shù),交給服務(wù)端實(shí)現(xiàn)的同名方法調(diào)用,最后將返回值打包返回給客戶端。

需要注意的是 onTransact() 是在服務(wù)端進(jìn)程的 Binder 線程池中進(jìn)行的,這就意味著如果我們的要在 onTransact() 方法的中更新 UI,就必須借助 Handler。

這兩個(gè)方法的第一個(gè)參數(shù)的含義是 AIDL 接口方法的標(biāo)識(shí)碼,在 Stub 中,定義了兩個(gè)常量作為這兩個(gè)方法的標(biāo)示:

static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
   static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);

如果 code == TRANSACTION_addBook,那么說明客戶端調(diào)用的是 addBook();如果 code == TRANSACTION_getBookList,那么客戶端調(diào)用的是 getBookList(),然后交由相應(yīng)的服務(wù)端方法處理。 用一張圖來表示整個(gè)通信過程:

Android 進(jìn)程通信機(jī)制之 AIDL

了解了 AIDL 的整個(gè)過程,接下來就是 AIDL 在安卓程序中的應(yīng)用了。

 AIDL 的使用

相信大家應(yīng)該都和清楚 Service 的使用了吧,Service 雖然稱作“服務(wù)”,并且運(yùn)行于后臺(tái),但是它們默認(rèn)還是運(yùn)行在默認(rèn)進(jìn)程的主線程中。其實(shí)讓 Service 運(yùn)行在默認(rèn)進(jìn)程中,有點(diǎn)大材小用了。android 的很多系統(tǒng)服務(wù)都運(yùn)行于單獨(dú)的進(jìn)程中,供其他應(yīng)用調(diào)用,比如窗口管理服務(wù)。這樣做的好處是可以多個(gè)應(yīng)用共享同一個(gè)服務(wù),節(jié)約了資源,也便于集中管理各個(gè)客戶端,要注意問題的就是線程安全問題。

那么接下來我們就用 AIDL 實(shí)現(xiàn)一個(gè)簡單的 CS 架構(gòu)的圖書管理系統(tǒng)。

首先我們定義服務(wù)端:

BookManagerService



public class BookManagerService extends Service {

  private final List<Book> mLibrary = new ArrayList<>();

  private IBookManager mBookManager = new IBookManager.Stub() {
    @Override
    public void addBook(Book book) throws RemoteException {
      synchronized (mLibrary) {
        mLibrary.add(book);
        Log.d("BookManagerService", "now our library has " + mLibrary.size() + " books");
      }

    }

    @Override
    public List<Book> getBookList() throws RemoteException {
      return mLibrary;
    }
  };
 
  @Override /* http://www.manongjc.com/article/1496.html */
  public IBinder onBind(Intent intent) {
    return mBookManager.asBinder();
  }

}


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

服務(wù)端我們定義了 BookManagerService 這個(gè)類,在它里面我們創(chuàng)建了服務(wù)端的 Stub 對(duì)象,并且實(shí)現(xiàn)了需要實(shí)現(xiàn)的兩個(gè) AIDL 接口方法來定義服務(wù)端的圖書管理策略。在 onBind() 方法中我們將 IBookManager 對(duì)象作為 IBinder 返回。我們知道,當(dāng)我們綁定一個(gè)服務(wù)時(shí),系統(tǒng)會(huì)調(diào)用 onBinder() 方法得到服務(wù)端的 IBinder 對(duì)象,并將其轉(zhuǎn)換成客戶端的 IBinder 對(duì)象傳給客戶端,雖然服務(wù)端的 IBinder 和 客戶端的 IBinder 是兩個(gè) IBinder 對(duì)象,但他們在底層都是同一個(gè)對(duì)象。我們在 xml 中注冊 Service 時(shí)給它指定了進(jìn)程名,這樣 Service 就能運(yùn)行在單獨(dú)的進(jìn)程中了。

接下來看看客戶端的實(shí)現(xiàn):

Client



public class Client extends AppCompatActivity {

  private TextView textView;

  private IBookManager bookManager;

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

    Intent i = new Intent(Client.this, BookManagerService.class);
    bindService(i, conn, BIND_AUTO_CREATE);

    Button addABook = (Button) findViewById(R.id.button);
    addABook.setOnClickListener(v -> {
      if (bookManager == null) return;
      try {
        bookManager.addBook(new Book(0, "book"));
        textView.setText(getString(R.string.book_management_system_book_count, String.valueOf(bookManager.getBookList().size())));
      } catch (RemoteException e) {
        e.printStackTrace();
      }

    });

    textView = (TextView) findViewById(R.id.textView);
  }

  private ServiceConnection conn = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
      Log.d("Client -->", service.toString());

      bookManager = IBookManager.Stub.asInterface(service);
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
      Log.d("Client", name.toString());
    }
  };

}



<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical" android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:weightSum="1"
  android:gravity="center">

  <Button
    android:text="http://www.manongjc.com/article/1495.html"
    android:layout_width="111dp"
    android:layout_height="wrap_content"
    android:id="@+id/button" />

  <TextView
    android:layout_marginTop="10dp"
    android:text="@string/book_management_system_book_count"
    android:layout_width="231dp"
    android:gravity="center"
    android:layout_height="wrap_content"
    android:id="@+id/textView" />
</LinearLayout>

我們的客戶端就是一個(gè) Activity,onCreate() 中進(jìn)行了服務(wù)的綁定,bindService() 方法中有一參數(shù) ServiceConnection:conn,因?yàn)榻壎ǚ?wù)是異步進(jìn)行的,這個(gè)參數(shù)的作用就是綁定服務(wù)成功后回調(diào)的接口,它有兩個(gè)回調(diào)方法:一個(gè)是連接服務(wù)成功后回調(diào),另一個(gè)在與服務(wù)端斷開連接后回調(diào)。我們現(xiàn)在關(guān)心的主要是 onServiceConnected() 方法,在這里我們只做了一件事:將服務(wù)端轉(zhuǎn)換過來的 IBinder 對(duì)象轉(zhuǎn)換成 AIDL 接口,我們定義 IBookManager:bookManager 字段來保持對(duì)其的引用。這樣的話,我們就可以通過這個(gè) bookManager 來進(jìn)行方法的遠(yuǎn)程調(diào)用。我們給客戶端的 Button 注冊事件:每一次點(diǎn)擊都會(huì)向服務(wù)端增加一本書,并且將圖書館現(xiàn)有的圖書數(shù)量顯示出來。

現(xiàn)在我們看看程序的運(yùn)行效果:

每當(dāng)我們點(diǎn)擊按鈕,我們就成功的向服務(wù)端添加了一本書,說明我們通過 AIDL 跨進(jìn)程通信成功了。

感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!

相關(guān)文章

  • 淺析KJFrameForAndroid框架如何高效加載Bitmap

    淺析KJFrameForAndroid框架如何高效加載Bitmap

    Bitmap是Android系統(tǒng)中的圖像處理的最重要類之一。用它可以獲取圖像文件信息,進(jìn)行圖像剪切、旋轉(zhuǎn)、縮放等操作,并可以指定格式保存圖像文件。本文主要是從KJFrameForAndroid框架中分析高效加載Bitmap的方法
    2014-07-07
  • Android數(shù)據(jù)持久化之File機(jī)制分析

    Android數(shù)據(jù)持久化之File機(jī)制分析

    這篇文章主要介紹了Android數(shù)據(jù)持久化之File機(jī)制,較為詳細(xì)的分析了File機(jī)制的原理及Android使用File實(shí)現(xiàn)數(shù)據(jù)持久化的相關(guān)操作技巧,需要的朋友可以參考下
    2017-05-05
  • Android自定義Dialog的2種常見方法

    Android自定義Dialog的2種常見方法

    這篇文章主要分享了Android自定義Dialog的2種常見方法,大多數(shù)中,使用系統(tǒng)內(nèi)置的dialog并不能滿足UE的設(shè)計(jì)需要,關(guān)于兩種方法下面文章將詳細(xì)介紹,需要的小伙伴可以參考一下
    2022-05-05
  • 解析android創(chuàng)建快捷方式會(huì)啟動(dòng)兩個(gè)應(yīng)用的問題

    解析android創(chuàng)建快捷方式會(huì)啟動(dòng)兩個(gè)應(yīng)用的問題

    本篇文章是對(duì)關(guān)于android創(chuàng)建快捷方式會(huì)啟動(dòng)兩個(gè)應(yīng)用的問題進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-06-06
  • Android 8.1隱藏狀態(tài)欄圖標(biāo)的實(shí)例代碼

    Android 8.1隱藏狀態(tài)欄圖標(biāo)的實(shí)例代碼

    這篇文章主要介紹了Android 8.1隱藏狀態(tài)欄圖標(biāo),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • Android基于虹軟(ArcSoft)實(shí)現(xiàn)人臉識(shí)別

    Android基于虹軟(ArcSoft)實(shí)現(xiàn)人臉識(shí)別

    人工智能時(shí)代快速來臨,其中人臉識(shí)別是當(dāng)前比較熱門的技術(shù),在國內(nèi)也越來越多的運(yùn)用,例如刷臉打卡,刷臉APP,身份識(shí)別,人臉門禁等。本文將為大家介紹Android基于虹軟(ArcSoft)實(shí)現(xiàn)人臉識(shí)別的demo,快來跟隨小編一起學(xué)習(xí)吧
    2021-12-12
  • Android掃描和生成二維碼

    Android掃描和生成二維碼

    這篇文章主要為大家詳細(xì)介紹了Android掃描二維碼和生成二維碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-11-11
  • Android編程之SurfaceView實(shí)例詳解

    Android編程之SurfaceView實(shí)例詳解

    這篇文章主要介紹了Android編程之SurfaceView用法,簡要分析了View和SurfaceView的區(qū)別,并結(jié)合實(shí)例形式分析了SurfaceView的具體使用步驟與相關(guān)技巧,需要的朋友可以參考下
    2016-02-02
  • Android控件Gallery3D效果實(shí)例代碼

    Android控件Gallery3D效果實(shí)例代碼

    GalleryFlow中主要做了對(duì)圖片的旋轉(zhuǎn)和縮放操作,根據(jù)圖片的屏幕中的位置對(duì)其進(jìn)行旋轉(zhuǎn)縮放操作,具體實(shí)現(xiàn)如下,感興趣的朋友可以參考下哈
    2013-06-06
  • 讀取android根目錄下的文件或文件夾實(shí)例

    讀取android根目錄下的文件或文件夾實(shí)例

    本篇文章主要介紹了讀取android根目錄下的文件或文件夾,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2016-12-12

最新評(píng)論