編輯:關於Android編程
接觸Android久的朋友,就會在面試或者實際開發中遇到AIDL,那麼今天我們就來看看AIDL。
一、官方描述
1.1 文檔說明
AIDL-Android Interface Definition Language,android接口定義語言,它與你可能已經使用過的其他接口定義語言很類似,它允許你定義接口規則,在客戶端和服務器約定為了相互之間能使用IPC(進程間通信)通信。在Android中,正常情況下,一個進程無法訪問另外一個進程的內存。所以,它們需要將對象分解成操作系統可以識別的原始的類型,這些有序的對象可以穿過邊界為你。代碼做編組,是比較繁瑣的,但是如果你使用AIDL,那麼Android將會自己處理。
PS:1. 使用AIDL的條件是,允許不同的客戶端應用訪問你的服務,並且在服務端還需要處理多進程。(多客戶端、多線程、IPC)
2. 如果你不需要並發處理不同應用的IPC,你應當創建一個接口實現Binder。
3. 如果你只執行IPC,不需要處理對線程,那麼使用Messenger實現一個接口。
補:在實現AIDL時,要先綁定一個服務。
1.2 數據類型。
AIDL支持的數據類型有以下幾種,
1.支持Java原始數據類型。支持基本數據類型有byte,int,long,float,double,boolean,char,注意沒有‘short’。
2.支持String和CharSequence。
3.支持java.util.List和java.util.Map。集合中項的允許數據類型包括Java原始類型、String、CharSequence或是android.os.Parcelable。無需為List和Map提供import語句,但需 要為Parcelable提供import語句。
4.支持傳遞實現了Android.os.Parcelable接口的復雜類型,同樣在引用這些類型時也需要import語句。Parcelable 是Android提供的實現序列化方式。
二、創建AIDL。
為了模擬使用AIDL,需要創建兩個應用,一個是服務端,一個客戶端。打算實現一個簡單的加法計算功能。首先看看服務端的具體實現,
2.1 服務端的具體實現。
1. 打開Android Studio,創建一個Moudle,命名為AidlServer,然後創建一個CalculateAidl的AIDL文件,具體代碼如下;
package xinxing.aidltest;
interface CalculateAidl {
int add(int num1,int num2);
}
代碼比較簡單,就是定義了一個接口,裡面有一個方法。
2. 需要創建一個繼承Service的服務,這個服務是用來實現AIDL接口以及提供遠程調用,具體看實現,
package xinxing.aidltest;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class CalculateService extends Service {
public CalculateService() {
}
@Override
public IBinder onBind(Intent intent) {
return binder;
}
private IBinder binder= new CalculateAidl.Stub(){
@Override
public int add(int num1, int num2) throws RemoteException {
int result=num1+num2;
return result;
}
};
}
代碼比較少、也簡單,了解Service的應該很容易看懂。還是再次解釋下,在該Service中通過stub(存根) 返回了IBinder對象,並且在該過程中實現了AIDL接口的方法。
至此,服務端的開發就結束了!就是這麼簡約!
2.2 客戶端實現。
1. 打開Android Studio,創建一個Moudle,命名為AidlClient,接著把服務端的AIDL文件直接復制拷貝到該項目中(客戶端和服務費的AIDL文件的包一定要一樣)。
2. 實現布局編碼。此處就不羅列了!
3. 主要功能。在調用AIDL接口時,我們首先需要綁定一個遠程服務,
/**
* 綁定服務
*/
private void bindService() {
//先檢查服務端應用是否安裝
if (AppUtils.checkPackage(MainActivity.this, "xinxing.aidltest")) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("xinxing.aidltest", "xinxing.aidltest.CalculateService"));
bindService(intent, conn, Context.BIND_AUTO_CREATE);
} else {
isBindSuccess=false;
Toast.makeText(MainActivity.this, "第三方應用可能未安裝成功,請檢查後,再試!", Toast.LENGTH_LONG).show();
}
}
綁定遠程服務,首先判斷服務應用是否安裝,安裝了,才去綁定服務,沒有安裝,提示‘未安裝’。
//遠程連接
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
calculateAidl = CalculateAidl.Stub.asInterface(service);
isBindSuccess=true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
calculateAidl = null;
isBindSuccess=false;
}
};
遠程連接成功,通過IBinder對象獲取到AIDL實例,下面就是如何調用接口了,
if (!isBindSuccess) {
Toast.makeText(MainActivity.this, "第三方應用可能未安裝成功,請檢查後,再試!", Toast.LENGTH_LONG).show();
return;
}
if (TextUtils.isEmpty(etNum1.getText().toString())) {
Toast.makeText(MainActivity.this, "請輸入第一個數字", Toast.LENGTH_LONG).show();
return;
}
int num1 = Integer.parseInt(etNum1.getText().toString());
if (TextUtils.isEmpty(etNum2.getText().toString())) {
Toast.makeText(MainActivity.this, "請輸入第二個數字", Toast.LENGTH_LONG).show();
return;
}
int num2 = Integer.parseInt(etNum2.getText().toString());
try {
String result = String.valueOf(calculateAidl.add(num1, num2));
tvResult.setText(result);
} catch (RemoteException e) {
e.printStackTrace();
}
代碼比較簡單,就不多說了!至此,客戶端的代碼也ok 了!
這是當服務端應用沒有安裝時,點擊計算按鈕的效果截圖,

這是當服務端應用已經安裝,點擊計算按鈕的效果截圖,

下面展示MainActivity的全部代碼,
package xinxing.aidlclient;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import xinxing.aidltest.CalculateAidl;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private EditText etNum1;
private EditText etNum2;
private TextView tvResult;
private Button btn;
private CalculateAidl calculateAidl;//aidl對象
private boolean isBindSuccess=false;//是否綁定成功
//遠程連接
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
calculateAidl = CalculateAidl.Stub.asInterface(service);
isBindSuccess=true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
calculateAidl = null;
isBindSuccess=false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etNum1 = (EditText) findViewById(R.id.et_num1);
etNum2 = (EditText) findViewById(R.id.et_num2);
tvResult = (TextView) findViewById(R.id.tv_result);
btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(this);
bindService();
}
@Override
public void onClick(View v) {
if (!isBindSuccess) {
Toast.makeText(MainActivity.this, "第三方應用可能未安裝成功,請檢查後,再試!", Toast.LENGTH_LONG).show();
return;
}
if (TextUtils.isEmpty(etNum1.getText().toString())) {
Toast.makeText(MainActivity.this, "請輸入第一個數字", Toast.LENGTH_LONG).show();
return;
}
int num1 = Integer.parseInt(etNum1.getText().toString());
if (TextUtils.isEmpty(etNum2.getText().toString())) {
Toast.makeText(MainActivity.this, "請輸入第二個數字", Toast.LENGTH_LONG).show();
return;
}
int num2 = Integer.parseInt(etNum2.getText().toString());
try {
String result = String.valueOf(calculateAidl.add(num1, num2));
tvResult.setText(result);
} catch (RemoteException e) {
e.printStackTrace();
}
}
/**
* 綁定服務
*/
private void bindService() {
//先檢查服務端應用是否安裝
if (AppUtils.checkPackage(MainActivity.this, "xinxing.aidltest")) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("xinxing.aidltest", "xinxing.aidltest.CalculateService"));
bindService(intent, conn, Context.BIND_AUTO_CREATE);
} else {
isBindSuccess=false;
Toast.makeText(MainActivity.this, "第三方應用可能未安裝成功,請檢查後,再試!", Toast.LENGTH_LONG).show();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (isBindSuccess) {
unbindService(conn);
}
}
}
記得在Activity銷毀的時候,解除綁定。
三、總結。
使用AIDL,首先需要定義接口以及接口使用到的數據類型,如果是比較復雜的數據類型,需要自己通過Parcelable去實現序列化。繼承一個Service實現AIDL接口定義的方法。調用該AIDL方法是,最好能加入判斷(被調用的應用是否安裝的判斷)。
1. 使用AIDL的情況是多線程、 多應用 、IPC。
2. 使用AIDL時,客戶端和服務端的AIDL文件以及包名都要一樣。
詳解Android中的Context抽象類
關於Context我們首先應該知道:(1)它描述的是一個應用程序環境的信息,即上下文。(2)該類是一個抽象(abstract class)類,Android提供了該抽象類
Android OpenGLES2.0(一)——了解OpenGLES2.0
什麼是OpenGL ES? OpenGL(全寫Open Graphics Library)是指定義了一個跨編程語言、跨平台的編程接口規格的專業的圖形程序接口。它用於三維圖
Android UI實現單行文本水平觸摸滑動效果
本文實例為大家分享了單行文本水平觸摸滑動效果,通過EditText實現TextView單行長文本水平滑動效果。下一篇再為大家介紹 多行文本折疊展開效果,自定義布局View
osgi之ServiceListener的應用
前言我原想直接跳過這些osgi中基礎知識,直接從osgi應用的一些中級篇或者高級篇開始的,後來想到osgi中的ServiceListener、ServiceTracker