[Android 接口定義語言 (AIDL)](https://developer.android.com/guide/components/aidl.html)
**另請參閱**
[綁定服務](https://developer.android.com/guide/components/bound-services.html)
AIDL(Android 接口定義語言)與您可能使用過的其他 IDL 類似。 您可以利用它定義客戶端與服務使用進程間通信 (IPC) 進行相互通信時都認可的編程接口。 在 Android 上,一個進程通常無法訪問另一個進程的內存。 盡管如此,進程需要將其對象分解成操作系統能夠識別的原語,并將對象編組成跨越邊界的對象。 編寫執行這一編組操作的代碼是一項繁瑣的工作,因此 Android 會使用 AIDL 來處理。
> 注:只有允許不同應用的客戶端用 IPC 方式訪問服務,并且想要在服務中處理多線程時,才有必要使用 AIDL。 如果您不需要執行跨越不同應用的并發 IPC,就應該通過[實現一個 Binder](https://developer.android.com/guide/components/bound-services.html#Binder) 創建接口;或者,如果您想執行 IPC,但根本不需要處理多線程,則[使用 Messenger 類](https://developer.android.com/guide/components/bound-services.html#Messenger)來實現接口。無論如何,在實現 AIDL 之前,請您務必理解[綁定服務](https://developer.android.com/guide/components/bound-services.html)。
在您開始設計 AIDL 接口之前,要注意 AIDL 接口的調用是直接函數調用。 您不應該假設發生調用的線程。 視調用來自本地進程還是遠程進程中的線程,實際情況會有所差異。 具體而言:
* 來自本地進程的調用在發起調用的同一線程內執行。如果該線程是您的主 UI 線程,則該線程繼續在 AIDL 接口中執行。 如果該線程是其他線程,則其便是在服務中執行您的代碼的線程。 因此,只有在本地線程訪問服務時,您才能完全控制哪些線程在服務中執行(但如果真是這種情況,您根本不應該使用 AIDL,而是應該通過實現 Binder 類創建接口)。
* 來自遠程進程的調用分派自平臺在您的自有進程內部維護的線程池。 您必須為來自未知線程的多次并發傳入調用做好準備。 換言之,AIDL 接口的實現必須是完全線程安全實現。
* oneway 關鍵字用于修改遠程調用的行為。使用該關鍵字時,遠程調用不會阻塞;它只是發送事務數據并立即返回。接口的實現最終接收此調用時,是以正常遠程調用形式將其作為來自 Binder 線程池的常規調用進行接收。 如果 oneway 用于本地調用,則不會有任何影響,調用仍是同步調用。
#### **定義 AIDL 接口**
您必須使用 Java 編程語言語法在 .aidl 文件中定義 AIDL 接口,然后將它保存在托管服務的應用以及任何其他綁定到服務的應用的源代碼(src/ 目錄)內。
您開發每個包含 .aidl 文件的應用時,Android SDK 工具都會生成一個基于該 .aidl 文件的 [IBinder](https://developer.android.com/reference/android/os/IBinder.html) 接口,并將其保存在項目的 gen/ 目錄中。服務必須視情況實現 IBinder 接口。然后客戶端應用便可綁定到該服務,并調用 IBinder 中的方法來執行 IPC。
如需使用 AIDL 創建綁定服務,請執行以下步驟:
1. [創建 .aidl 文件](https://developer.android.com/guide/components/aidl.html#CreateAidl)
此文件定義帶有方法簽名的編程接口。
2. [實現接口](https://developer.android.com/guide/components/aidl.html#ImplementTheInterface)
Android SDK 工具基于您的 .aidl 文件,使用 Java 編程語言生成一個接口。此接口具有一個名為 Stub 的內部抽象類,用于擴展 [Binder ](https://developer.android.com/reference/android/os/Binder.html)類并實現 AIDL 接口中的方法。您必須擴展 Stub 類并實現方法。
3. [向客戶端公開該接口](https://developer.android.com/guide/components/aidl.html#ExposeTheInterface)
實現 [Service](https://developer.android.com/reference/android/app/Service.html) 并重寫 onBind() 以返回 Stub 類的實現。
> 注意:在 AIDL 接口首次發布后對其進行的任何更改都必須保持向后兼容性,以避免中斷其他應用對您的服務的使用。 也就是說,因為必須將您的 .aidl 文件復制到其他應用,才能讓這些應用訪問您的服務的接口,因此您必須保留對原始接口的支持。
1. 創建 .aidl 文件
AIDL 使用簡單語法,使您能通過可帶參數和返回值的一個或多個方法來聲明接口。 參數和返回值可以是任意類型,甚至可以是其他 AIDL 生成的接口。
您必須使用 Java 編程語言構建 .aidl 文件。每個 .aidl 文件都必須定義單個接口,并且只需包含接口聲明和方法簽名。
默認情況下,AIDL 支持下列數據類型:
* Java 編程語言中的所有原語類型(如 int、long、char、boolean 等等)
* [String](https://developer.android.com/reference/java/lang/String.html)
* [CharSequence](https://developer.android.com/reference/java/lang/CharSequence.html)
* [List](https://developer.android.com/reference/java/util/List.html)
List 中的所有元素都必須是以上列表中支持的數據類型、其他 AIDL 生成的接口或您聲明的可打包類型。 可選擇將 List 用作“通用”類(例如,List<String>)。另一端實際接收的具體類始終是 ArrayList,但生成的方法使用的是 List 接口。
* [Map](https://developer.android.com/reference/java/util/Map.html)
Map 中的所有元素都必須是以上列表中支持的數據類型、其他 AIDL 生成的接口或您聲明的可打包類型。 不支持通用 Map(如 Map<String,Integer> 形式的 Map)。 另一端實際接收的具體類始終是 HashMap,但生成的方法使用的是 Map 接口。
您必須為以上未列出的每個附加類型加入一個 import 語句,即使這些類型是在與您的接口相同的軟件包中定義。
定義服務接口時,請注意:
* 方法可帶零個或多個參數,返回值或空值。
* 所有非原語參數都需要指示數據走向的方向標記。可以是 in、out 或 inout(見以下示例)。
原語默認為 in,不能是其他方向。
> 注意:您應該將方向限定為真正需要的方向,因為編組參數的開銷極大。
* .aidl 文件中包括的所有代碼注釋都包含在生成的 IBinder 接口中(import 和 package 語句之前的注釋除外)
* 只支持方法;您不能公開 AIDL 中的靜態字段。
以下是一個 .aidl 文件示例:
~~~
// IRemoteService.aidl
package com.example.android;
// Declare any non-default types here with import statements
/** Example service interface */
interface IRemoteService {
/** Request the process ID of this service, to do evil things with it. */
int getPid();
/** 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);
}
~~~
只需將您的 .aidl 文件保存在項目的 src/ 目錄內,當您開發應用時,SDK 工具會在項目的 gen/ 目錄中生成 IBinder 接口文件。生成的文件名與 .aidl 文件名一致,只是使用了 .java 擴展名(例如,IRemoteService.aidl 生成的文件名是 IRemoteService.java)。
如果您使用 Android Studio,增量編譯幾乎會立即生成 Binder 類。 如果您不使用 Android Studio,則 Gradle 工具會在您下一次開發應用時生成 Binder 類 — 您應該在編寫完 .aidl 文件后立即用 gradle assembleDebug (或 gradle assembleRelease)編譯項目,以便您的代碼能夠鏈接到生成的類。
2. 實現接口
當您開發應用時,Android SDK 工具會生成一個以 .aidl 文件命名的 .java 接口文件。生成的接口包括一個名為 Stub 的子類,這個子類是其父接口(例如,YourInterface.Stub)的抽象實現,用于聲明 .aidl 文件中的所有方法。
> 注:Stub 還定義了幾個幫助程序方法,其中最引人關注的是 asInterface(),該方法帶 IBinder(通常便是傳遞給客戶端 onServiceConnected() 回調方法的參數)并返回存根接口實例。 如需了解如何進行這種轉換的更多詳細信息,請參見調用 IPC 方法一節。
如需實現 .aidl 生成的接口,請擴展生成的 Binder 接口(例如,YourInterface.Stub)并實現從 .aidl 文件繼承的方法。
以下是一個使用匿名實例實現名為 IRemoteService 的接口(由以上 IRemoteService.aidl 示例定義)的示例:
~~~
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
public int getPid(){
return Process.myPid();
}
public void basicTypes(int anInt, long aLong, boolean aBoolean,
float aFloat, double aDouble, String aString) {
// Does nothing
}
};
~~~
現在,mBinder 是 Stub 類的一個實例(一個 Binder),用于定義服務的 RPC 接口。 在下一步中,將向客戶端公開該實例,以便客戶端能與服務進行交互。
在實現 AIDL 接口時應注意遵守以下這幾個規則:
* 由于不能保證在主線程上執行傳入調用,因此您一開始就需要做好多線程處理準備,并將您的服務正確地編譯為線程安全服務。
* 默認情況下,RPC 調用是同步調用。如果您明知服務完成請求的時間不止幾毫秒,就不應該從 Activity 的主線程調用服務,因為這樣做可能會使應用掛起(Android 可能會顯示“Application is Not Responding”對話框)— 您通常應該從客戶端內的單獨線程調用服務。
* 您引發的任何異常都不會回傳給調用方。
3. 向客戶端公開該接口
您為服務實現該接口后,就需要向客戶端公開該接口,以便客戶端進行綁定。 要為您的服務公開該接口,請擴展 Service 并實現 onBind(),以返回一個類實例,這個類實現了生成的 Stub(見前文所述)。以下是一個向客戶端公開 IRemoteService 示例接口的服務示例。
~~~
public class RemoteService extends Service {
@Override
public void onCreate() {
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
// Return the interface
return mBinder;
}
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
public int getPid(){
return Process.myPid();
}
public void basicTypes(int anInt, long aLong, boolean aBoolean,
float aFloat, double aDouble, String aString) {
// Does nothing
}
};
}
~~~
現在,當客戶端(如 Activity)調用 bindService() 以連接此服務時,客戶端的 onServiceConnected() 回調會接收服務的 onBind() 方法返回的 mBinder 實例。
客戶端還必須具有對 interface 類的訪問權限,因此如果客戶端和服務在不同的應用內,則客戶端的應用 src/ 目錄內必須包含 .aidl 文件(它生成 android.os.Binder 接口 — 為客戶端提供對 AIDL 方法的訪問權限)的副本。
當客戶端在 onServiceConnected() 回調中收到 IBinder 時,它必須調用 YourServiceInterface.Stub.asInterface(service) 以將返回的參數轉換成 YourServiceInterface 類型。例如:
~~~
IRemoteService mIRemoteService;
private ServiceConnection mConnection = new ServiceConnection() {
// Called when the connection with the service is established
public void onServiceConnected(ComponentName className, IBinder service) {
// Following the example above for an AIDL interface,
// this gets an instance of the IRemoteInterface, which we can use to call on the service
mIRemoteService = IRemoteService.Stub.asInterface(service);
}
// Called when the connection with the service disconnects unexpectedly
public void onServiceDisconnected(ComponentName className) {
Log.e(TAG, "Service has unexpectedly disconnected");
mIRemoteService = null;
}
};
~~~
如需查看更多示例代碼,請參見 [ApiDemos](https://developer.android.com/resources/samples/ApiDemos/index.html) 中的 [RemoteService.java](https://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html) 類。
#### **通過 IPC 傳遞對象**
通過 IPC 接口把某個類從一個進程發送到另一個進程是可以實現的。 不過,您必須確保該類的代碼對 IPC 通道的另一端可用,并且該類必須支持 [Parcelable](https://developer.android.com/reference/android/os/Parcelable.html) 接口。支持 Parcelable 接口很重要,因為 Android 系統可通過它將對象分解成可編組到各進程的原語。
如需創建支持 Parcelable 協議的類,您必須執行以下操作:
1. 讓您的類實現 Parcelable 接口。
2. 實現 writeToParcel,它會獲取對象的當前狀態并將其寫入 [Parcel](https://developer.android.com/reference/android/os/Parcel.html)。
3. 為您的類添加一個名為 CREATOR 的靜態字段,這個字段是一個實現 [Parcelable.Creator](https://developer.android.com/reference/android/os/Parcelable.Creator.html) 接口的對象。
4. 最后,創建一個聲明可打包類的 .aidl 文件(按照下文 Rect.aidl 文件所示步驟)。
如果您使用的是自定義編譯進程,切勿在您的編譯中添加 .aidl 文件。 此 .aidl 文件與 C 語言中的頭文件類似,并未編譯。
AIDL 在它生成的代碼中使用這些方法和字段將您的對象編組和取消編組。
例如,以下這個 Rect.aidl 文件可創建一個可打包的 Rect 類:
~~~
package android.graphics;
// Declare Rect so AIDL can find it and knows that it implements
// the parcelable protocol.
parcelable Rect;
~~~
以下示例展示了 [Rect](https://developer.android.com/reference/android/graphics/Rect.html) 類如何實現 Parcelable 協議。
~~~
import android.os.Parcel;
import android.os.Parcelable;
public final class Rect implements Parcelable {
public int left;
public int top;
public int right;
public int bottom;
public static final Parcelable.Creator<Rect> CREATOR = new
Parcelable.Creator<Rect>() {
public Rect createFromParcel(Parcel in) {
return new Rect(in);
}
public Rect[] newArray(int size) {
return new Rect[size];
}
};
public Rect() {
}
private Rect(Parcel in) {
readFromParcel(in);
}
public void writeToParcel(Parcel out) {
out.writeInt(left);
out.writeInt(top);
out.writeInt(right);
out.writeInt(bottom);
}
public void readFromParcel(Parcel in) {
left = in.readInt();
top = in.readInt();
right = in.readInt();
bottom = in.readInt();
}
}
~~~
Rect 類中的編組相當簡單。看一看 Parcel 上的其他方法,了解您可以向 Parcel 寫入哪些其他類型的值。
> 警告:別忘記從其他進程接收數據的安全影響。 在本例中,Rect 從 Parcel 讀取四個數字,但要由您來確保無論調用方目的為何這些數字都在相應的可接受值范圍內。 如需了解有關如何防止應用受到惡意軟件侵害、保證應用安全的更多信息,請參見安全與權限。
#### **調用 IPC 方法**
調用類必須執行以下步驟,才能調用使用 AIDL 定義的遠程接口:
1. 在項目 src/ 目錄中加入 .aidl 文件。
2. 聲明一個 IBinder 接口實例(基于 AIDL 生成)。
3. 實現 ServiceConnection。
4. 調用 Context.bindService(),以傳入您的 ServiceConnection 實現。
5. 在您的 onServiceConnected() 實現中,您將收到一個 IBinder 實例(名為 service)。調用 YourInterfaceName.Stub.asInterface((IBinder)service),以將返回的參數轉換為 YourInterface 類型。
6. 調用您在接口上定義的方法。您應該始終捕獲 DeadObjectException 異常,它們是在連接中斷時引發的;這將是遠程方法引發的唯一異常。
7. 如需斷開連接,請使用您的接口實例調用 Context.unbindService()。
有關調用 IPC 服務的幾點說明:
* 對象是跨進程計數的引用。
* 您可以將匿名對象作為方法參數發送。
如需了解有關綁定到服務的詳細信息,請閱讀[綁定服務](https://developer.android.com/guide/components/bound-services.html#Binding)文檔。
以下這些示例代碼摘自 ApiDemos 項目的遠程服務示例代碼,展示了如何調用 AIDL 創建的服務。
~~~
public static class Binding extends Activity {
/** The primary interface we will be calling on the service. */
IRemoteService mService = null;
/** Another interface we use on the service. */
ISecondary mSecondaryService = null;
Button mKillButton;
TextView mCallbackText;
private boolean mIsBound;
/**
* Standard initialization of this activity. Set up the UI, then wait
* for the user to poke it before doing anything.
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.remote_service_binding);
// Watch for button clicks.
Button button = (Button)findViewById(R.id.bind);
button.setOnClickListener(mBindListener);
button = (Button)findViewById(R.id.unbind);
button.setOnClickListener(mUnbindListener);
mKillButton = (Button)findViewById(R.id.kill);
mKillButton.setOnClickListener(mKillListener);
mKillButton.setEnabled(false);
mCallbackText = (TextView)findViewById(R.id.callback);
mCallbackText.setText("Not attached.");
}
/**
* Class for interacting with the main interface of the service.
*/
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
// This is called when the connection with the service has been
// established, giving us the service object we can use to
// interact with the service. We are communicating with our
// service through an IDL interface, so get a client-side
// representation of that from the raw service object.
mService = IRemoteService.Stub.asInterface(service);
mKillButton.setEnabled(true);
mCallbackText.setText("Attached.");
// We want to monitor the service for as long as we are
// connected to it.
try {
mService.registerCallback(mCallback);
} catch (RemoteException e) {
// In this case the service has crashed before we could even
// do anything with it; we can count on soon being
// disconnected (and then reconnected if it can be restarted)
// so there is no need to do anything here.
}
// As part of the sample, tell the user what happened.
Toast.makeText(Binding.this, R.string.remote_service_connected,
Toast.LENGTH_SHORT).show();
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mService = null;
mKillButton.setEnabled(false);
mCallbackText.setText("Disconnected.");
// As part of the sample, tell the user what happened.
Toast.makeText(Binding.this, R.string.remote_service_disconnected,
Toast.LENGTH_SHORT).show();
}
};
/**
* Class for interacting with the secondary interface of the service.
*/
private ServiceConnection mSecondaryConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
// Connecting to a secondary interface is the same as any
// other interface.
mSecondaryService = ISecondary.Stub.asInterface(service);
mKillButton.setEnabled(true);
}
public void onServiceDisconnected(ComponentName className) {
mSecondaryService = null;
mKillButton.setEnabled(false);
}
};
private OnClickListener mBindListener = new OnClickListener() {
public void onClick(View v) {
// Establish a couple connections with the service, binding
// by interface names. This allows other applications to be
// installed that replace the remote service by implementing
// the same interface.
Intent intent = new Intent(Binding.this, RemoteService.class);
intent.setAction(IRemoteService.class.getName());
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
intent.setAction(ISecondary.class.getName());
bindService(intent, mSecondaryConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
mCallbackText.setText("Binding.");
}
};
private OnClickListener mUnbindListener = new OnClickListener() {
public void onClick(View v) {
if (mIsBound) {
// If we have received the service, and hence registered with
// it, then now is the time to unregister.
if (mService != null) {
try {
mService.unregisterCallback(mCallback);
} catch (RemoteException e) {
// There is nothing special we need to do if the service
// has crashed.
}
}
// Detach our existing connection.
unbindService(mConnection);
unbindService(mSecondaryConnection);
mKillButton.setEnabled(false);
mIsBound = false;
mCallbackText.setText("Unbinding.");
}
}
};
private OnClickListener mKillListener = new OnClickListener() {
public void onClick(View v) {
// To kill the process hosting our service, we need to know its
// PID. Conveniently our service has a call that will return
// to us that information.
if (mSecondaryService != null) {
try {
int pid = mSecondaryService.getPid();
// Note that, though this API allows us to request to
// kill any process based on its PID, the kernel will
// still impose standard restrictions on which PIDs you
// are actually able to kill. Typically this means only
// the process running your application and any additional
// processes created by that app as shown here; packages
// sharing a common UID will also be able to kill each
// other's processes.
Process.killProcess(pid);
mCallbackText.setText("Killed service process.");
} catch (RemoteException ex) {
// Recover gracefully from the process hosting the
// server dying.
// Just for purposes of the sample, put up a notification.
Toast.makeText(Binding.this,
R.string.remote_call_failed,
Toast.LENGTH_SHORT).show();
}
}
}
};
// ----------------------------------------------------------------------
// Code showing how to deal with callbacks.
// ----------------------------------------------------------------------
/**
* This implementation is used to receive callbacks from the remote
* service.
*/
private IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub() {
/**
* This is called by the remote service regularly to tell us about
* new values. Note that IPC calls are dispatched through a thread
* pool running in each process, so the code executing here will
* NOT be running in our main thread like most other things -- so,
* to update the UI, we need to use a Handler to hop over there.
*/
public void valueChanged(int value) {
mHandler.sendMessage(mHandler.obtainMessage(BUMP_MSG, value, 0));
}
};
private static final int BUMP_MSG = 1;
private Handler mHandler = new Handler() {
@Override public void handleMessage(Message msg) {
switch (msg.what) {
case BUMP_MSG:
mCallbackText.setText("Received from service: " + msg.arg1);
break;
default:
super.handleMessage(msg);
}
}
};
}
~~~
- 前言
- Google官網對Android API各版本的介紹
- jelly Bean(果凍豆)Android 4.1、4.2、4.3
- Android 4.1
- Android 4.2
- Android 4.3
- KitKat(Android 4.4.*)巧克力
- Android 4.4 APIS
- Lollipop(棒棒糖)Android 5.*
- Android 5.0 APIs
- Android 5.0 Changes(變更)
- Android 5.1APIs
- Marshmallow(棉花糖)Android 6.0
- Android 6.0 APIs
- Android 6.0 Changes(變更)
- Android 6.0 Samples
- Android 6.0 Testing
- Nougat(牛扎塘)Android 7.*
- Android 7.0
- API
- 行為變更
- 示例
- Android 7.1
- 開發者API
- 示例Sample
- Oreo(奧利奧)8.*
- Android 8.0
- 功能和 API
- Android 8.0 行為變更
- 向 Android 8.0 遷移應用
- Android 8.0 示例
- Android 8.1
- 后臺執行限制
- 后臺位置限制
- API指南
- Android 簡介
- 應用基礎知識
- 設備兼容性
- 系統權限
- 請求權限
- 定義權限
- 平臺架構
- Java8 概覽
- 在ART上驗證應用行為
- 應用組件
- Intent 和 Intent 過濾器(Google官網介紹)
- 通用intent
- Activity
- 任務和返回棧(官網譯文)
- 概覽屏幕
- 活動簡介
- 活動生命周期
- 活動狀態更改
- 進程和應用程序生命周期
- 包裹和捆綁
- 最近的屏幕
- 片段
- 加載器
- 服務Service
- 綁定服務
- AIDL
- 內容提供程序
- 內容提供程序基礎知識
- 創建內容提供程序
- 日歷提供程序
- 聯系人提供程序
- 存儲訪問框架
- 使用存儲訪問框架打開文件
- 創建自定義文檔提供程序
- 應用小部件
- 應用小部件主機
- 進程和線程
- 應用資源
- 概覽
- 提供資源
- 訪問資源
- 處理運行時變更
- 本地化
- ICU4J Android框架API
- Android上的國際化
- 語言和語言區域
- 復雜的XML資源
- 資源類型
- 動畫
- 顏色狀態列表
- 可繪制對象
- 布局
- 菜單
- 字符串
- 樣式
- 其他類型
- 應用清單
- <action>
- <activity>
- <activity-alias>
- <application>
- <category>
- <compatiable-screens>
- <data>
- <grant-uri-permission>
- <intent-filter>
- <manifest>
- <meta-data>
- <path-permission>
- <permission>
- <permission-group>
- <permission-tree>
- <provider>
- <receiver>
- <service>
- <supporte-gl-texture>
- <supports-screens>
- <uses-configuration>
- <uses-feature>
- <uses-library>
- <uses-permission>
- <uses-permission-sdk-23>
- <uses-sdk>
- 用戶界面
- 界面概覽
- 界面布局
- 線性布局
- 相對布局
- 列表視圖
- 網格視圖
- 回收站視圖
- 外觀和感覺
- 可下載的字體
- XML中的字體
- 表情符號兼容性
- 自動調整TextView
- 樣式和主題-
- 輸入控件
- 按鈕
- 文本字段
- 復選框
- 單選按鈕
- 切換按鈕
- 微調框
- 選取器
- 輸入事件
- 菜單Menu
- 設置
- 對話框
- 通知
- Toast
- 自適應圖標
- 應用快捷方式
- 搜索
- 創建搜索界面
- 添加近期查詢建議
- 添加自定義建議
- 可搜索配置
- 多窗口支持
- 拖放
- 無障礙功能
- 為應用設置無障礙功能
- 無障礙功能開發者檢查單
- 構建無障礙服務
- 讓應用更容易訪問
- 使用節點樹調試
- 構建可訪問自定義視圖
- 樣式和主題
- 自定義組件
- 動畫和圖形
- 概覽介紹
- 屬性動畫
- 視圖動畫
- 可繪制動畫
- 畫布和可繪制對象
- 基于物理的動畫
- Spring Animation
- Fling Animation
- OpenGL ES
- 硬件加速
- 計算
- RenderScript
- 高級RenderScript
- Runtime API Reference(參考)
- Numerical Types(數字類型)
- Object Types(對象類型)
- Conversion Functions(轉換函數)
- Mathematical Constants and Functions(數學常量和函數)
- Vector Math Functions(矢量數學函數)
- Matrix Functions(矩陣函數)
- Quaternion Functions(四元數函數)
- Atomic Update Functions(原子更新函數)
- Time Functions and Types(時間函數和類型)
- Allocation Data Access Functions(分配數據訪問函數)
- Object Characteristics Functions(對象特性函數)
- Kernel Invocation Functions and Types(內核調用函數和類型)
- Input/Output Functions(輸入輸出函數)
- Debugging Functions(調試函數)
- Graphics Functions and Types(圖形函數和類型)
- Index(索引)
- Media Apps(媒體應用)
- Media Apps Overview(媒體應用程序概述)
- Working with a Media Session(使用媒體會話)
- Building an Audio App(建立一個音頻應用)
- Building a Media Browser Service(構建媒體瀏覽器服務)
- Building a Media Browser Client(構建媒體瀏覽器客戶端)
- Media Session Callbacks(媒體會話回調)
- Building a Video App(建立一個視頻應用)
- Building a Video Player Activity(建立一個視頻播放器Activity)
- Media Session Callbacks-(媒體會話回調)
- Responding to Media Buttons(響應媒體按鈕)
- Handling Changes in Audio Output(處理音頻輸出的變化)
- Managing Audio Focus(管理音頻焦點)
- The Google Assistant and Media Apps(Google智能助理和媒體應用)
- 媒體和相機
- Supported Media Formats(支持的媒體格式)
- MediaPlayer(媒體播放器)
- MediaRecorder
- ExoPlayer
- Controller Amplitude with VolumeShaper(VolumeShaper控制器振幅)
- Media Routing(媒體路由)
- MediaRouter API
- MediaRouteProvider API
- Camera API(相機API)
- 位置和傳感器
- Location and Maps(位置和地圖)
- Location Strategies(位置策略)
- Sensors Overview(傳感器概覽)
- Motion Sensors(運動傳感器)
- Position Sensors(位置傳感器)
- Environment Sensors(環境傳感器)
- Raw GNSS Measurements(原始的GNSS測量)
- 連接
- Bluetooth
- Bluetooth Low Energy(藍牙低功耗)
- NFC
- NFC Basics(NFC基礎知識)
- Advanced NFC(高級NFC)
- Host-based Card Emulation(基于主機的卡模擬)
- Telecom(電信)
- Self-Managed ConnectionServices(自我管理的連接服務)
- Wi-Fi P2P
- Wi-Fi Aware
- Companion Device Pairing
- USB
- Accessory(配件)
- Host(主機)
- SIP
- 文本和輸入
- Autofill Framework(自動填充框架)
- Test your app with autofill(使用自動填充測試你的應用)
- Building autofill services(構建自動填充服務)
- Copy and Paste(復制和粘貼)
- Creating an IME(創建IME)
- Image Keyboard(圖像鍵盤)
- Spelling Checker(拼寫檢查程序)
- 數據存儲
- Storage Options(存儲選項)
- Data Backup(數據備份)
- Account Transfer API(賬戶轉移API)
- Auto Backup(自動備份)
- Key/Value Backup(鍵值備份)
- Testing Backup and Restore(測試備份和還原)
- App Install Location(應用安裝位置)
- 庫
- 支持庫
- 功能
- 修訂歷史記錄
- 庫設置
- 數據綁定庫
- 測試支持庫
- 管理
- 設備策略
- 網絡應用
- Supporting Different Screens in Web Apps(在網絡應用中支持不同屏幕)
- Building Web Apps in WebView(在WebView中構建網絡應用)
- Managing WebViews
- Migrating to WebView in Android 4.4(遷移到Android4.4中的WebView)
- Debugging Web Apps(調試網絡應用)
- Best Practices for Web Apps(網絡應用最佳做法)
- 最佳實踐
- Supporting Multiple Screens(支持多種屏幕)
- Distributing to Specific Screens(分配到特定屏幕)
- Screen Compatibility Mode(屏幕兼容性模式)
- Designing for Seamlessness
- Supporting Tablets and Handsets
- 培訓