不得不說的Android Binder機制與AIDL

說起Android的進程間通信卸奉,想必大家都會不約而同的想起Android中的Binder機制。而提起B(yǎng)inder颖御,想必也有不少同學會想起初學Android時被Binder和AIDL支配的恐懼感榄棵。但是作為一個Android開發(fā)者,Binder是我們必須掌握的知識潘拱。因為它是構(gòu)架整個Android大廈的鋼筋和混凝土疹鳄,連接了Android各個系統(tǒng)服務(wù)和上層應(yīng)用。只有了解了Binder機制才能更加深入的理解Android開發(fā)和Android Framework芦岂。這也是為什么無論是《Android開發(fā)藝術(shù)探索》還是《深入理解Android內(nèi)核涉及思想》這些進階類書籍把進程間通信和Binder機制放到靠前章節(jié)的原因瘪弓,它太重要了,重要到整個Android Framework都離不開Binder的身影禽最。

本篇文章我們暫且不去探討B(tài)inder的底層實現(xiàn)腺怯,因為就目前而言,筆者掌握的程度也不足以去輸出Binder實現(xiàn)原理的的內(nèi)容川无。因此呛占,為了不誤導(dǎo)大家,這里就來寫一寫B(tài)inder的基礎(chǔ)用法以及AIDL懦趋。雖然關(guān)于Binder和AIDL的基礎(chǔ)用法網(wǎng)上的內(nèi)容比比皆是晾虑。但是能把Binder和AIDL寫的淺顯易懂的文章并不多見。也就導(dǎo)致了很多人覺得Binder跟AIDL的使用都很難。

本篇文章帜篇,我將通過我自己的學習思路來帶大家認識Binder機制和AIDL糙捺。

一、進程間通信

在操作系統(tǒng)中笙隙,每個進程都有一塊獨立的內(nèi)存空間洪灯。為了保證程序的的安全性,操作系統(tǒng)都會有一套嚴格的安全機制來禁止進程間的非法訪問逃沿。畢竟婴渡,如果你的APP能訪問到別的APP的運行空間,或者別的APP可以輕而易舉的訪問到你APP的運行空間凯亮,想象一下你是不是崩潰的心都有了边臼。所以,操作系統(tǒng)層面會對應(yīng)用進程進行內(nèi)存隔離假消,以保證APP的運行安全柠并。但是,很多情況下進程間也是需要相互通信的富拗,例如剪貼板的功能臼予,可以從一個程序中復(fù)制信息到另一個程序。這就是進程間通信誕生的背景啃沪。

廣義的講粘拾,進程間通信(Inter-process communication,簡稱IPC)是指運行在不同進程中的若干線程間的數(shù)據(jù)交換。

操作系統(tǒng)中常見的進程間通信方式有共享內(nèi)存创千、管道缰雇、UDS以及Binder等。關(guān)于這些進程間的通信方式本篇文章我們不做深究追驴,了解即可械哟。

  • 共享內(nèi)存(Shared Memory) 共享內(nèi)存方式實現(xiàn)進程間通信依靠的是申請一塊內(nèi)存區(qū)域,讓后將這塊內(nèi)存映射到進程空間中殿雪,這樣兩個進程都可以直接訪問這塊內(nèi)存暇咆。在進行進程間通信時,兩個進程可以利用這塊內(nèi)存空間進行數(shù)據(jù)交換丙曙。通過這樣的方式爸业,減少了數(shù)據(jù)的賦值操作,因此共享內(nèi)存實現(xiàn)進程間通信在速度上有明顯優(yōu)勢河泳。

  • 管道(Pipe) 管道也是操作系統(tǒng)中常見的一種進程間通信方式沃呢,Windows系統(tǒng)進程間的通信依賴于此中方式實現(xiàn)。在進行進程間通信時拆挥,會在兩個進程間建立一根擁有讀(read)寫(write)功能的管道,一個進程寫數(shù)據(jù)薄霜,另一個進程可以讀取數(shù)據(jù)某抓,從而實現(xiàn)進程間通信問題。

  • UDS(UNIX Domain Socket) UDS也被稱為IPC Socket惰瓜,但它有別于network 的Socket否副。UDS的內(nèi)部實現(xiàn)不依賴于TCP/IP協(xié)議,而是基于本機的“安全可靠操作”實現(xiàn)崎坊。UDS這種進程間通信方式在Android中用到的也是比較多的备禀。

  • Binder Binder是Android中獨有的一種進程間通信方式。它底層依靠mmap,只需要一次數(shù)據(jù)拷貝奈揍,把一塊物理內(nèi)存同時映射到內(nèi)核和目標進程的用戶空間曲尸。

本篇文章,我們重點就是了解如何使用Binder實現(xiàn)進程間通信男翰。Binder僅僅從名字來看就給人一種很神秘的感覺另患,就因為這個名字可能就會嚇走不少初學者。但其實Binder本身并沒有很神秘蛾绎,它僅僅是Android系統(tǒng)提供給開發(fā)者的一種進程間通信方式昆箕。

而從上述幾種進程間通信方式來看,無論是哪種進程間通信租冠,都是需要一個進程提供數(shù)據(jù)鹏倘,一個進程獲取數(shù)據(jù)。因此顽爹,我們可以把提供數(shù)據(jù)的一端稱為服務(wù)端纤泵,把獲取數(shù)據(jù)的一端稱為客戶端。從這個角度來看Binder是不是就有點類似于HTTP協(xié)議了镜粤?所以夕吻,你完全可以把Binder當成是一種HTTP協(xié)議,客戶端通過Binder來獲取服務(wù)端的數(shù)據(jù)繁仁。認識到這一點,再看Binder的使用就會簡單多了归园。

二黄虱、使用Binder實現(xiàn)進程間通信

使用Binder完成進程間通信其實非常簡單庸诱。我們舉一個查詢成績的例子捻浦,服務(wù)端提供根據(jù)學生姓名查詢學生成績的接口,客戶端連接服務(wù)端通過學生姓名來查詢成績桥爽,而客戶端與服務(wù)端的媒介就是Binder朱灿。

1.服務(wù)端的實現(xiàn)

服務(wù)端自然是要提供服務(wù)的,因此就需要我們開啟一個Service等待客戶端的連接钠四。關(guān)于Android的Service這里就不用多說了吧盗扒,我們實現(xiàn)一個GradeService并繼承Service跪楞,來提供成績查詢接口。代碼如下:

public class GradeService extends Service {
    public static final int REQUEST_CODE=1000;
    private final Binder mBinder = new Binder() {
        @Override
        protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
            if (code == REQUEST_CODE) {
                String name = data.readString();
                // 根據(jù)姓名查詢學生成績并將成績寫入到返回數(shù)據(jù)
                int studentGrade = getStudentGrade(name);
                if (reply != null)
                    reply.writeInt(studentGrade);
                return true;
            }
            return super.onTransact(code, data, reply, flags);
        }
        // 根據(jù)姓名查詢學生成績
        public int getStudentGrade(String name) {         
            return StudentMap.getStudentGrade(name);
        }
    };

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

因為我們要實現(xiàn)的是跨進程通信侣灶,因此甸祭,我們將這個服務(wù)端的Service設(shè)置到遠程進程中,在AndroidManifest文件中如下:

<service
    android:name="com.zhpan.sample.binder.server.GradeService"
    android:process=":server">
    <intent-filter>
        <action android:name="android.intent.action.server.gradeservice" />
    </intent-filter>
</service>

就這樣褥影,一個遠程的池户,提供成績查詢的服務(wù)就完成了。

2.客戶端的實現(xiàn)

客戶端自然而然的是要連接服務(wù)端進程成績查詢凡怎。因此校焦,我們在客戶端的Activity中取綁定GradeService進行成績查詢。代碼如下:

public class BinderActivity extends AppCompatActivity {
    // 遠程服務(wù)的Binder代理
    private IBinder mRemoteBinder;

    private final ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            // 獲取遠程服務(wù)的Binder代理
            mRemoteBinder = iBinder;
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mRemoteBinder = null;
        }
    };



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_binder);
        // 綁定服務(wù)
        findViewById(R.id.btn_bind_service).setOnClickListener(view -> bindGradeService());
        // 查詢學生成績
        findViewById(R.id.btn_find_grade).setOnClickListener(view -> getStudentGrade("Anna"));
    }
    // 綁定遠程服務(wù)
    private void bindGradeService() {
        String action = "android.intent.action.server.gradeservice";
        Intent intent = new Intent(action);
        intent.setPackage(getPackageName());
        bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
    }
    // 從遠程服務(wù)查詢學生成績
    private int getStudentGrade(String name) {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        int grade = 0;
        data.writeString(name);
        try {
            if (mRemoteBinder == null) {
                throw new IllegalStateException("Need Bind Remote Server...");
            }
            mRemoteBinder.transact(REQUEST_CODE, data, reply, 0);
            grade = reply.readInt();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return grade;
    }

客戶端的代碼就是通過綁定遠程服務(wù)统倒,然后獲取到服務(wù)的Binder代理寨典,來查詢學生成績¢苁恚可見凝赛,使用Binder實現(xiàn)進程間通信是非常簡單的,可以說簡單的有點出乎所料坛缕。那我們之前寫的AIDL是什么呢墓猎?AIDL生成的那一堆是什么玩意兒?我們且往下看赚楚。

三毙沾、代理模式優(yōu)化Binder使用

雖然上一章中的代碼已經(jīng)非常簡單了,但是還是有可以優(yōu)化的空間宠页。我們可以通過設(shè)計模式來進行優(yōu)化左胞,讓代碼更加簡潔。

首先需要定義一個接口查詢成績的接口IGradeInterface举户,代碼如下:

public interface IGradeInterface {
    // 查詢成績接口
    int getStudentGrade(String name);
}

1.服務(wù)端代碼優(yōu)化

接著烤宙,對服務(wù)端的代碼進行優(yōu)化。我們實現(xiàn)一個自定義的GradeBinder俭嘁,并實現(xiàn)上述接口躺枕,代碼如下:

public class GradeBinder extends Binder implements IGradeInterface {

    @Override
    public int getStudentGrade(String name) {
        return StudentMap.getStudentGrade(name);
    }

    @Override
    protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
        if (code == REQUEST_CODE) {
            String name = data.readString();
            int studentGrade = getStudentGrade(name);
            if (reply != null)
                reply.writeInt(studentGrade);
            return true;
        }
        return super.onTransact(code, data, reply, flags);
    }
}

上述代碼將查詢成績的相關(guān)邏輯從Service搬到了GradeBinder中。因此供填,此時Service中只需要在onBind的時候返回GradeBinder的實例即可拐云。代碼如下:

public class GradeService extends Service {

    public static final int REQUEST_CODE=1000;

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

2.客戶端代碼優(yōu)化

客戶端優(yōu)化的思路是在連接到遠程服務(wù)時候?qū)嵗粋€代理類,代理類持有Binder近她,讓代理類行使Binder的權(quán)利叉瘩。首先來看代理類的代碼實現(xiàn):

public class BinderProxy implements IGradeInterface {
    // 被代理的Binder
    private final IBinder mBinder;
    // 私有化構(gòu)造方法
    private BinderProxy(IBinder binder) {
        mBinder = binder;
    }

    // 通過Binde讀取成績
    @Override
    public int getStudentGrade(String name) {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        int grade = 0;
        data.writeString(name);
        try {
            if (mBinder == null) {
                throw new IllegalStateException("Need Bind Remote Server...");
            }
            mBinder.transact(REQUEST_CODE, data, reply, 0);
            grade = reply.readInt();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return grade;
    }
        
    // 實例化Binder代理類的對象
    public static IGradeInterface asInterface(IBinder iBinder) {
        if (iBinder == null) {
            return null;
        } 
        
        if (iBinder instanceof IGradeInterface) {
            LogUtils.e("當前進程");
            // 如果是同一個進程的請求,則直接返回Binder
            return (IGradeInterface) iBinder;
        } else {
            LogUtils.e("遠程進程");
            // 如果是跨進程查詢則返回Binder的代理對象
            return new BinderProxy(iBinder);
        }
    }

}

BinderProxy類的構(gòu)造方法被設(shè)置成了private粘捎。同時提供了一個asInterface方法中薇缅,這個方法通過判斷Binder是不是IGradeInterface類型從而確定是不是跨進程的通信危彩。如果不是跨進程通信,則返回當前這個Binder捅暴,否則就返回Binder的這個代理類恬砂。

接下來客戶端連接上遠程服務(wù)的時候使用BinderProxy獲取Binder或者BinderProxy實例。代碼如下:

public class BinderProxyActivity extends BaseViewBindingActivity<ActivityBinderBinding> {
    // 此處可能是BinderProxy也可能是GradeBinder
    private IGradeInterface mBinderProxy;

    private final ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            // 連接服務(wù)成功蓬痒,根據(jù)是否跨進程獲取BinderProxy或者GradeBinder實例
            mBinderProxy = BinderProxy.asInterface(iBinder);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mBinderProxy = null;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding.btnBindService.setOnClickListener(view -> bindGradeService());
        // 查詢學生成績點擊事件泻骤,通過mBinderProxy查詢成績
        binding.btnFindGrade.setOnClickListener(view -> ToastUtils.showShort("Anna grade is " + mBinderProxy.getStudentGrade("Anna")));
    }

    // 綁定服務(wù)
    private void bindGradeService() {
        String action = "android.intent.action.server.gradeservice";
        Intent intent = new Intent(action);
        intent.setPackage(getPackageName());
        bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
    }

}

可以看到,此時的代碼相比第一章的代碼整潔了不少梧奢。但是狱掂,代碼寫起來似乎還沒有第一章中的方便。主要是因為要我們增加一個IGradeInterface接口亲轨,還要自定義一個GradeBinder趋惨,同時,還需要寫代理類的相關(guān)代碼惦蚊,感覺非常繁瑣器虾。那么有沒有辦法讓代碼簡潔,寫起來還不繁瑣呢蹦锋?答案是肯定的兆沙,使用AIDL就可以實現(xiàn)。

四莉掂、AIDL

AIDL是Android Interface Description Languaged 簡寫葛圃。用于描寫客戶端/服務(wù)端通信接口的一種描述語言。提起AIDL相信很多人都會覺得頭大憎妙,定義一個AIDL接口库正,生成了那么多不知所云的代碼,看起來簡直就是災(zāi)難厘唾。先別擔心褥符,如果你看懂了第三章的內(nèi)容,那么其實你已經(jīng)完全掌握了AIDL抚垃。沒錯属瓣,說白了AIDL生成的那一坨代碼其實就是我們第三章中寫的代碼。即AIDL的原理其實就是使用了代理模式對Binder的使用進行了優(yōu)化讯柔,使用AIDL保證了代碼的整潔,同時也省去了自己編寫繁瑣的代理類相關(guān)代碼护昧。

關(guān)于AIDL的使用就非常簡單了魂迄。

1.創(chuàng)建AIDL接口

首先,在要創(chuàng)建AIDL的目錄上右鍵->New->AIDL->AIDl File 來創(chuàng)建一個AIDL文件惋耙,如下圖所示:

image

創(chuàng)建一個名為IGradeService的AIDL文件捣炬,并添加一個getStudentGrade的方法熊昌。代碼如下:

// IGradeService.aidl
package com.zhpan.sample.binder.aidl;

// Declare any non-default types here with import statements

interface IGradeService {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

    int getStudentGrade(String name);
}

接著Rebuild一下項目后IDE就會自動生成AIDL的代碼了。

2.AIDL生成的代碼

在項目的build目錄下com.zhpan.sample.binder.aidl包中會看到自動生成的一個名為IGradeService的接口湿酸,代碼如下:

// 這個接口相當于上一章中的IGradeInterface接口
public interface IGradeService extends android.os.IInterface {
  
  ...
  
  // Stub是一個Binder婿屹,相當于上一章中的GradeBinder
  public static abstract class Stub extends android.os.Binder
      implements com.zhpan.sample.binder.aidl.IGradeService {
    private static final java.lang.String DESCRIPTOR = "com.zhpan.sample.binder.aidl.IGradeService";

    public Stub() {
      this.attachInterface(this, DESCRIPTOR);
    }

    public static IGradeService asInterface(android.os.IBinder obj) {
      
      if ((obj == null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin != null) && (iin instanceof com.zhpan.sample.binder.aidl.IGradeService))) {
        // 如果是當前進程則直接返回當前Binder對象
        return ((com.zhpan.sample.binder.aidl.IGradeService) iin);
      }
      // 跨進程則返回Binder的代理對象
      return new com.zhpan.sample.binder.aidl.IGradeService.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 {
      java.lang.String descriptor = DESCRIPTOR;
      switch (code) {
        case INTERFACE_TRANSACTION: {
          reply.writeString(descriptor);
          return true;
        }
        case TRANSACTION_basicTypes: {
          data.enforceInterface(descriptor);
          int _arg0;
          _arg0 = data.readInt();
          long _arg1;
          _arg1 = data.readLong();
          boolean _arg2;
          _arg2 = (0 != data.readInt());
          float _arg3;
          _arg3 = data.readFloat();
          double _arg4;
          _arg4 = data.readDouble();
          java.lang.String _arg5;
          _arg5 = data.readString();
          this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
          reply.writeNoException();
          return true;
        }
        case TRANSACTION_getStudentGrade: {
          data.enforceInterface(descriptor);
          java.lang.String _arg0;
          _arg0 = data.readString();
          int _result = this.getStudentGrade(_arg0);
          reply.writeNoException();
          reply.writeInt(_result);
          return true;
        }
        default: {
          return super.onTransact(code, data, reply, flags);
        }
      }
    }
    // Binder的代理類,相當于上一章中的BinderProxy
    private static class Proxy implements com.zhpan.sample.binder.aidl.IGradeService {
      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;
      }

      @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
          double aDouble, java.lang.String aString) throws android.os.RemoteException {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          _data.writeInt(anInt);
          _data.writeLong(aLong);
          _data.writeInt(((aBoolean) ? (1) : (0)));
          _data.writeFloat(aFloat);
          _data.writeDouble(aDouble);
          _data.writeString(aString);
          boolean _status = mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().basicTypes(anInt, aLong, aBoolean, aFloat, aDouble, aString);
            return;
          }
          _reply.readException();
        } finally {
          _reply.recycle();
          _data.recycle();
        }
      }

      @Override public int getStudentGrade(java.lang.String name)
          throws android.os.RemoteException {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        int _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          _data.writeString(name);
          boolean _status = mRemote.transact(Stub.TRANSACTION_getStudentGrade, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().getStudentGrade(name);
          }
          _reply.readException();
          _result = _reply.readInt();
        } finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }

      public static com.zhpan.sample.binder.aidl.IGradeService sDefaultImpl;
    }

    static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_getStudentGrade = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);

    public static boolean setDefaultImpl(com.zhpan.sample.binder.aidl.IGradeService impl) {
      if (Stub.Proxy.sDefaultImpl == null && impl != null) {
        Stub.Proxy.sDefaultImpl = impl;
        return true;
      }
      return false;
    }

    public static com.zhpan.sample.binder.aidl.IGradeService getDefaultImpl() {
      return Stub.Proxy.sDefaultImpl;
    }
  }

  /**
   * Demonstrates some basic types that you can use as parameters
   * and return values in AIDL.
   */
  public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble,
      java.lang.String aString) throws android.os.RemoteException;

  public int getStudentGrade(java.lang.String name) throws android.os.RemoteException;
}

瞥一眼代碼會發(fā)現(xiàn)IGradeService接口中有一個名為Stub的內(nèi)部類推溃,它繼承了Binder昂利,并實現(xiàn)了IGradeService接口,并且它的內(nèi)部有一個asInterface的方法铁坎,這個方法與我們上一章BinderProxy中的asInterface一致蜂奸,只是寫的位置不同而已。另外在Stub的onTranscation方法的TRANSACTION_getStudentGrade條件中的代碼與GradeBinder的onTranscation方法代碼是一樣的硬萍。

接著扩所,Stub類中還有一個名為Proxy的內(nèi)部類。Proxy類與上一章的BinderProxy相對應(yīng)朴乖∽嫫粒可以看到Proxy類的構(gòu)造方法并沒有修飾符,而BinderProxy的構(gòu)造方法被聲明成了private买羞,都可以防止外部通過構(gòu)造方法區(qū)實例化代理類的對象袁勺。Proxy的getStudentGrade方法與BinderProxy中的getStudentGrade一樣,通過Binder去讀取服務(wù)端的寫入數(shù)據(jù)哩都。

3.AIDL客戶端

使用AIDL的客戶端實現(xiàn)幾乎與第三章中的代碼一致魁兼。只不過是在連接到服務(wù)端后通過IGradeService.Stub下的asInterface方法來獲取Binder或者Binder的代理對象焕妙。代碼如下:

public class AidlActivity extends BaseViewBindingActivity<ActivityBinderBinding> {

    private IGradeService mBinderProxy;

    private final ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            // 連接服務(wù)后寄啼,根據(jù)是否跨進程獲取Binder或者Binder的代理對象
            mBinderProxy = IGradeService.Stub.asInterface(iBinder);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mBinderProxy = null;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding.btnBindService.setOnClickListener(view -> bindGradeService());
        // 查詢學生成績
        binding.btnFindGrade.setOnClickListener(view -> getStudentGrade("Anna"));
    }
  
    // 綁定服務(wù)
    private void bindGradeService() {
        String action = "android.intent.action.server.aidl.gradeservice";
        Intent intent = new Intent(action);
        intent.setPackage(getPackageName());
        bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
    }
  
    // 查詢成績
    private void getStudentGrade(String name) {
        int grade = 0;
        try {
            grade = mBinderProxy.getStudentGrade(name);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        ToastUtils.showShort("Anna grade is " + grade);
    }
}

到這里,關(guān)于AIDL的介紹就結(jié)束了蠢挡。有沒有驚奇的發(fā)現(xiàn)AIDL原來這么簡單儒鹿!

五化撕、總結(jié)

本篇文章主要帶大家認識了進程間通信和Binder與AIDL的使用。通過本篇文章的學習可以發(fā)現(xiàn)Binder與AIDL其實是非常簡單的约炎。了解了Binder之后植阴,我們就可以去更加深入的學習Android Framework層的知識了。

視頻
無所不能的Binder底層原理解析
進程間通信原理

原文https://juejin.cn/post/6994057245113729038

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末圾浅,一起剝皮案震驚了整個濱河市掠手,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌狸捕,老刑警劉巖喷鸽,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異灸拍,居然都是意外死亡做祝,警方通過查閱死者的電腦和手機砾省,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來混槐,“玉大人编兄,你說我怎么就攤上這事∩牵” “怎么了狠鸳?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長捌刮。 經(jīng)常有香客問我碰煌,道長,這世上最難降的妖魔是什么绅作? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任芦圾,我火速辦了婚禮,結(jié)果婚禮上俄认,老公的妹妹穿的比我還像新娘个少。我一直安慰自己,他們只是感情好眯杏,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布夜焦。 她就那樣靜靜地躺著,像睡著了一般岂贩。 火紅的嫁衣襯著肌膚如雪茫经。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天萎津,我揣著相機與錄音卸伞,去河邊找鬼。 笑死锉屈,一個胖子當著我的面吹牛荤傲,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播颈渊,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼遂黍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了俊嗽?” 一聲冷哼從身側(cè)響起雾家,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎绍豁,沒想到半個月后芯咧,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年唬党,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鬼佣。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡驶拱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出晶衷,到底是詐尸還是另有隱情蓝纲,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布晌纫,位于F島的核電站税迷,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏锹漱。R本人自食惡果不足惜箭养,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望哥牍。 院中可真熱鬧毕泌,春花似錦、人聲如沸嗅辣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽澡谭。三九已至愿题,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蛙奖,已是汗流浹背潘酗。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留外永,地道東北人崎脉。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像伯顶,于是被迫代替她去往敵國和親囚灼。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容