編輯:關於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文件以及包名都要一樣。
關於Context我們首先應該知道:(1)它描述的是一個應用程序環境的信息,即上下文。(2)該類是一個抽象(abstract class)類,Android提供了該抽象類
什麼是OpenGL ES? OpenGL(全寫Open Graphics Library)是指定義了一個跨編程語言、跨平台的編程接口規格的專業的圖形程序接口。它用於三維圖
本文實例為大家分享了單行文本水平觸摸滑動效果,通過EditText實現TextView單行長文本水平滑動效果。下一篇再為大家介紹 多行文本折疊展開效果,自定義布局View
前言我原想直接跳過這些osgi中基礎知識,直接從osgi應用的一些中級篇或者高級篇開始的,後來想到osgi中的ServiceListener、ServiceTracker