0、相關資料
視頻:AIDL-小白成長記
文章:Android AIDL使用詳解
1、概述
官方檔案:Android 介面定義語言 (AIDL)
以下摘抄自官方檔案:
Android 介面定義語言 (AIDL) 與您可能使用過的其他介面語言 (IDL) 類似,您可以利用它定義客戶端與服務均認可的編程介面,以便二者使用行程間通信 (IPC) 進行相互通信,在 Android 中,一個行程通常無法訪問另一個行程的記憶體,因此,為進行通信,行程需將其物件分解成可供作業系統理解的原語,并將其編組為可供您操作的物件,撰寫執行該編組操作的代碼較為繁瑣,因此 Android 會使用 AIDL 為您處理此問題,
注意:只有在需要不同應用的客戶端通過 IPC 方式訪問服務,并且希望在服務中進行多執行緒處理時,您才有必要使用 AIDL,如果您無需跨不同應用執行并發 IPC,則應通過實作 Binder 來創建介面;或者,如果您想執行 IPC,但不需要處理多執行緒,請使用 Messenger 來實作介面,無論如何,在實作 AIDL 之前,請您務必理解系結服務,
在開始設計 AIDL 介面之前,請注意,AIDL 介面的呼叫是直接函式呼叫,您無需對發生呼叫的執行緒做任何假設,實際情況的差異取決于呼叫是來自本地行程中的執行緒,還是遠程行程中的執行緒,具體而言:
- 來自本地行程的呼叫在發起呼叫的同一執行緒內執行,如果該執行緒是您的主界面執行緒,則其將繼續在 AIDL 介面中執行,如果該執行緒是其他執行緒,則其便是在服務中執行代碼的執行緒,因此,只有在本地執行緒訪問服務時,您才能完全控制哪些執行緒在服務中執行(但若出現此情況,您根本無需使用 AIDL,而應通過實作 Binder 類來創建介面),
- 遠程行程的呼叫分派自執行緒池,且平臺會在您自己的行程內部維護該執行緒池,您必須為來自未知執行緒,且多次呼叫同時發生的傳入呼叫做好準備,換言之,AIDL 介面的實作必須基于完全的執行緒安全,如果呼叫來自同一遠程物件上的某個執行緒,則該呼叫將依次抵達接收器端,
oneway關鍵字用于修改遠程呼叫的行為,使用此關鍵字后,遠程呼叫不會屏蔽,而只是發送事務資料并立即回傳,最終接收該資料時,介面的實作會將其視為來自Binder執行緒池的常規呼叫(普通的遠程呼叫),如果oneway用于本地呼叫,則不會有任何影響,且呼叫仍為同步呼叫,
2、代碼實戰
AIDL案例:
定義AIDL檔案
實作服務端
實作客戶端
思路圖:

2.1、服務端
2.1.1、創建 .aidl 檔案
// IImoocAidl.aidl
package com.test.server;
// Declare any non-default types here with import statements
interface IImoocAidl {
// 計算兩個數的和
int add(int num1,int num2);
}
然后make project,會生成IImoocAidl.java檔案

專案目錄:

2.1.2、實作介面
public class IRemoteService extends Service {
private static final String TAG = "IRemoteService";
@Nullable
@Override
public IBinder onBind(Intent intent) {
return iBinder;
}
private IBinder iBinder = new IImoocAidl.Stub() {
@Override
public int add(int num1, int num2) throws RemoteException {
Log.e(TAG, "收到了遠程的請求,請求的引數是:num1 = " + num1 + "num2 = " + num2);
return num1 + num2;
}
};
}
2.1.3、向客戶端公開介面
public class IRemoteService extends Service {
private static final String TAG = "IRemoteService";
/**
* 當客戶端系結到該服務的時候,會執行此方法
* @param intent
* @return
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
return iBinder;
}
private IBinder iBinder = new IImoocAidl.Stub() {
@Override
public int add(int num1, int num2) throws RemoteException {
Log.e(TAG, "收到了遠程的請求,請求的引數是:num1 = " + num1 + "num2 = " + num2);
return num1 + num2;
}
};
}
2.1.4、組態檔注冊Service并啟動Service
組態檔注冊:
<service
android:name=".IRemoteService"
android:exported="true" />
啟動Service:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, IRemoteService.class);
startService(intent);
}
}
2.2、客戶端
在同專案中新建一個名為client的module
2.2.1、創建客戶端界面
ClientActivity
public class ClientActivity extends AppCompatActivity {
EditText etNum1, etNum2;
TextView tvRes;
Button btnAdd;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_client);
etNum1 = findViewById(R.id.et_num1);
etNum2 = findViewById(R.id.et_num2);
tvRes = findViewById(R.id.tv_res);
btnAdd = findViewById(R.id.btn_add);
btnAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
}
}
布局檔案:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ClientActivity">
<EditText
android:id="@+id/et_num1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="輸入第一個數字"
android:textSize="22sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="+"
android:textSize="100sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/et_num1" />
<EditText
android:id="@+id/et_num2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="輸入第二個數字"
android:textSize="22sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_add" />
<TextView
android:id="@+id/tv_res"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="計算結果"
android:textSize="40sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/et_num2" />
<Button
android:id="@+id/btn_add"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="計算"
android:textSize="22sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_res" />
</androidx.constraintlayout.widget.ConstraintLayout>
2.2.2、把服務端的aidl檔案拷貝到客戶端

2.2.3、系結服務并拿取資料
public class ClientActivity extends AppCompatActivity {
private static final String TAG = "ClientActivity";
EditText etNum1, etNum2;
TextView tvRes;
Button btnAdd;
IImoocAidl iImoocAidl;
private ServiceConnection mConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
// 拿到了遠程服務
iImoocAidl = IImoocAidl.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
// 回收資源
iImoocAidl = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_client);
etNum1 = findViewById(R.id.et_num1);
etNum2 = findViewById(R.id.et_num2);
tvRes = findViewById(R.id.tv_res);
btnAdd = findViewById(R.id.btn_add);
bindService();
btnAdd.setOnClickListener(view -> {
int num1 = Integer.parseInt(etNum1.getText().toString());
int num2 = Integer.parseInt(etNum2.getText().toString());
try {
// 呼叫遠程服務
if (null != iImoocAidl) {
int res = iImoocAidl.add(num1, num2);
tvRes.setText("計算結果為:" + res);
} else {
Log.e(TAG, "iImoocAidl is null!");
}
} catch (RemoteException e) {
e.printStackTrace();
tvRes.setText("Error!");
}
});
}
private void bindService() {
// 獲取服務端
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.test.server",
"com.test.server.IRemoteService"));
bindService(intent, mConn, BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mConn);
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/292754.html
標籤:其他
上一篇:AIDL入門學習二
下一篇:AsyncTask詳解及簡單示例
