> 編寫:[jdneo](https://github.com/jdneo) - 原文:[http://developer.android.com/training/sync-adapters/creating-sync-adapter.html](http://developer.android.com/training/sync-adapters/creating-sync-adapter.html)
設備和服務器之間執行數據傳輸的代碼會封裝在應用的Sync Adapter組件中。Sync Adapter框架會基于你的調度和觸發操作,運行Sync Adapter組件中的代碼。要將同步適配組件添加到應用當中,你需要添加下列部件:
**Sync Adapter類**
將你的數據傳輸代碼封裝到一個與Sync Adapter框架兼容的接口當中。
**綁定[Service](http://developer.android.com/reference/android/app/Service.html)**
通過一個綁定服務,允許Sync Adapter框架運行Sync Adapter類中的代碼。
**Sync Adapter的XML元數據文件**
該文件包含了有關Sync Adapter的信息。框架會根據該文件確定應該如何加載并調度你的數據傳輸任務。
**應用清單文件的聲明**
需要在應用的清單文件中聲明綁定服務;同時還需要指出Sync Adapter的元數據。
這節課將會向你展示如何定義他們。
### 創建一個Sync Adapter類
在這部分課程中,你將會學習如何創建封裝了數據傳輸代碼的Sync Adapter類。創建該類需要繼承Sync Adapter的基類;為該類定義構造函數;以及實現相關的方法,在這些方法中,我們定義數據傳輸任務。
### 繼承Sync Adapter基類:AbstractThreadedSyncAdapter
要創建Sync Adapter組件,首先繼承[AbstractThreadedSyncAdapter](http://developer.android.com/reference/android/content/AbstractThreadedSyncAdapter.html),然后編寫它的構造函數。同使用[Activity](# "An activity represents a single screen with a user interface.").onCreate()配置[Activity](# "An activity represents a single screen with a user interface.")時一樣,每次你的Sync Adapter組件重新被創建的時候,使用構造函數執行相關的配置。例如,如果你的應用使用一個Content Provider來存儲數據,那么使用構造函數來獲取一個[ContentResolver](http://developer.android.com/reference/android/content/ContentResolver.html)實例。由于從Android 3.0開始添加了第二種形式的構造函數,來支持`parallelSyncs`參數,所以你需要創建兩種形式的構造函數來保證兼容性。
> **Note:** Sync Adapter框架是設計成和Sync Adapter組件的單例一起工作的。實例化Sync Adapter組件的更多細節,會在后面的章節中展開。
下面的代碼展示了如何實現[AbstractThreadedSyncAdapter](http://developer.android.com/reference/android/content/AbstractThreadedSyncAdapter.html)和它的構造函數:
~~~
/**
* Handle the transfer of data between a server and an
* app, using the Android sync adapter framework.
*/
public class SyncAdapter extends AbstractThreadedSyncAdapter {
...
// Global variables
// Define a variable to contain a content resolver instance
ContentResolver mContentResolver;
/**
* Set up the sync adapter
*/
public SyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
/*
* If your app uses a content resolver, get an instance of it
* from the incoming Context
*/
mContentResolver = context.getContentResolver();
}
...
/**
* Set up the sync adapter. This form of the
* constructor maintains compatibility with Android 3.0
* and later platform versions
*/
public SyncAdapter(
Context context,
boolean autoInitialize,
boolean allowParallelSyncs) {
super(context, autoInitialize, allowParallelSyncs);
/*
* If your app uses a content resolver, get an instance of it
* from the incoming Context
*/
mContentResolver = context.getContentResolver();
...
}
~~~
### 在onPerformSync()中添加數據傳輸代碼
Sync Adapter組件并不會自動地執行數據傳輸。它對你的數據傳輸代碼進行封裝,使得Sync Adapter框架可以在后臺執行數據傳輸,而不會牽連到你的應用。當框架準備同步你的應用數據時,它會調用你所實現的[onPerformSync()](http://developer.android.com/reference/android/content/AbstractThreadedSyncAdapter.html#onPerformSync(android.accounts.Account, android.os.Bundle, java.lang.String, android.content.ContentProviderClient, android.content.SyncResult))方法。
為了便于將數據從你的應用程序轉移到Sync Adapter組件中,Sync Adapter框架調用[onPerformSync()](http://developer.android.com/reference/android/content/AbstractThreadedSyncAdapter.html#onPerformSync(android.accounts.Account, android.os.Bundle, java.lang.String, android.content.ContentProviderClient, android.content.SyncResult)),它具有下面的參數:
**Account**
該[Account](http://developer.android.com/reference/android/accounts/Account.html)對象與觸發Sync Adapter的事件相關聯。如果服務端不需要使用賬戶,那么你不需要使用這個對象內的信息。
**Extras**
一個Bundle對象,它包含了一些標識,這些標識由觸發Sync Adapter的事件所發送。
**Authority**
系統中某個Content Provider的Authority。你的應用必須要有訪問它的權限。通常,該Authority對應于你的應用的Content Provider。
**Content provider client**
[ContentProviderClient](http://developer.android.com/reference/android/content/ContentProviderClient.html)針對于由`Authority`參數所指向的Content Provider。[ContentProviderClient](http://developer.android.com/reference/android/content/ContentProviderClient.html)是一個Content Provider的輕量級共有接口。它的基本功能和[ContentResolver](http://developer.android.com/reference/android/content/ContentResolver.html)一樣。如果你正在使用Content Provider來存儲你的應用數據,你可以利用它連接Content Provider。反之,則將其忽略。
**Sync result**
一個[SyncResult](http://developer.android.com/reference/android/content/SyncResult.html)對象,你可以使用它將信息發送給Sync Adapter框架。
下面的代碼片段展示了[onPerformSync()](http://developer.android.com/reference/android/content/AbstractThreadedSyncAdapter.html#onPerformSync(android.accounts.Account, android.os.Bundle, java.lang.String, android.content.ContentProviderClient, android.content.SyncResult))函數的整體結構:
~~~
/*
* Specify the code you want to run in the sync adapter. The entire
* sync adapter runs in a background thread, so you don't have to set
* up your own background processing.
*/
@Override
public void onPerformSync(
Account account,
Bundle extras,
String authority,
ContentProviderClient provider,
SyncResult syncResult) {
/*
* Put the data transfer code here.
*/
...
}
~~~
雖然實際的[onPerformSync()](http://developer.android.com/reference/android/content/AbstractThreadedSyncAdapter.html#onPerformSync(android.accounts.Account, android.os.Bundle, java.lang.String, android.content.ContentProviderClient, android.content.SyncResult))實現是要根據應用數據的同步需求以及服務器的連接協議來制定,但是你的實現應當包含下列這些基本任務:
**連接到一個服務器**
盡管你可以假定在你開始傳輸數據時,已經獲取到了網絡連接,但是Sync Adapter框架并不會自動地連接到一個服務器。
**下載和上傳數據**
Sync Adapter不會自動執行數據傳輸。如果你想要從服務器下載數據并將它存儲到Content Provider中,你必須提供請求數據,下載數據和將數據插入到Provider中的代碼。類似地,如果你想把數據發送到服務器,你需要從一個文件,數據庫或者Provider中讀取數據,并且發送必需的上傳請求。同時你還需要處理在你執行數據傳輸時所發生的網絡錯誤。
**處理數據沖突或者確定當前數據是否最新**
Sync Adapter不會自動地解決服務器數據與設備數據之間的沖突。同時,它也不會自動檢測服務器上的數據是否比設備上的數據要新,反之亦然。因此,你必須自己提供處理這些狀況的算法。
**清理**
在數據傳輸的尾聲,記得要關閉網絡連接,清除臨時文件和緩存。
> **Note:** Sync Adapter框架會在一個后臺線程中執行[onPerformSync()](http://developer.android.com/reference/android/content/AbstractThreadedSyncAdapter.html#onPerformSync(android.accounts.Account, android.os.Bundle, java.lang.String, android.content.ContentProviderClient, android.content.SyncResult))方法,所以你不需要配置后臺處理任務。
除了和同步相關的任務之外,你應該嘗試將一些周期性的網絡相關的任務合并起來,并將它們添加到[onPerformSync()](http://developer.android.com/reference/android/content/AbstractThreadedSyncAdapter.html#onPerformSync(android.accounts.Account, android.os.Bundle, java.lang.String, android.content.ContentProviderClient, android.content.SyncResult))中。將所有網絡任務集中到該方法內處理,可以節省由啟動和停止網絡接口所造成的電量損失。有關更多如何在進行網絡訪問時更高效地使用電池方面的知識,可以閱讀:[Transferring Data Without Draining the Battery](#),它描述了一些在數據傳輸代碼中可以包含的網絡訪問任務。
### 將Sync Adapter綁定到框架上
現在,你已經將你的數據傳輸代碼封裝在了Sync Adapter組建中,但是你必須讓框架可以訪問你的代碼。為了做到這一點,你需要創建一個綁定[Service](http://developer.android.com/reference/android/app/Service.html),它將一個特殊的Android Binder對象從Sync Adapter組件傳遞給框架。有了這一Binder對象,框架就可以調用[onPerformSync()](http://developer.android.com/reference/android/content/AbstractThreadedSyncAdapter.html#onPerformSync(android.accounts.Account, android.os.Bundle, java.lang.String, android.content.ContentProviderClient, android.content.SyncResult))方法并將數據傳遞給它。
在服務的[onCreate()](http://developer.android.com/reference/android/app/Service.html#onCreate())方法中將你的Sync Adapter組件實例化為一個單例。通過在[onCreate()](http://developer.android.com/reference/android/app/Service.html#onCreate())方法中實例化該組件,你可以推遲到服務啟動后再創建它,這會在框架第一次嘗試執行你的數據傳輸時發生。你需要通過一種線程安全的方法來實例化組件,以防止Sync Adapter框架在響應觸發和調度時,形成含有多個Sync Adapter執行的隊列。
作為例子,下面的代碼片段展示了你應該如何實現一個綁定[Service](http://developer.android.com/reference/android/app/Service.html)的類,實例化你的Sync Adapter組件,并獲取Android Binder對象:
~~~
package com.example.android.syncadapter;
/**
* Define a Service that returns an IBinder for the
* sync adapter class, allowing the sync adapter framework to call
* onPerformSync().
*/
public class SyncService extends Service {
// Storage for an instance of the sync adapter
private static SyncAdapter sSyncAdapter = null;
// Object to use as a thread-safe lock
private static final Object sSyncAdapterLock = new Object();
/*
* Instantiate the sync adapter object.
*/
@Override
public void onCreate() {
/*
* Create the sync adapter as a singleton.
* Set the sync adapter as syncable
* Disallow parallel syncs
*/
synchronized (sSyncAdapterLock) {
if (sSyncAdapter == null) {
sSyncAdapter = new SyncAdapter(getApplicationContext(), true);
}
}
}
/**
* Return an object that allows the system to invoke
* the sync adapter.
*
*/
@Override
public IBinder onBind(Intent intent) {
/*
* Get the object that allows external processes
* to call onPerformSync(). The object is created
* in the base class code when the SyncAdapter
* constructors call super()
*/
return sSyncAdapter.getSyncAdapterBinder();
}
}
~~~
> **Note:**要看更多Sync Adapter綁定服務的例子,可以閱讀樣例代碼。
### 添加框架所需的賬戶
Sync Adapter框架需要每個Sync Adapter擁有一個賬戶類型。在[創建Stub授權器](#)章節中,你已經聲明了賬戶類型的值。現在你需要在Android系統中配置該賬戶類型。要配置賬戶類型,通過調用[addAccountExplicitly()](http://developer.android.com/reference/android/accounts/AccountManager.html#addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle))添加一個使用其賬戶類型的虛擬賬戶。
調用該方法最合適的地方是在應用的啟動[Activity](# "An activity represents a single screen with a user interface.")的[onCreate()](http://developer.android.com/reference/android/app/Service.html#onCreate())方法中。如下面的代碼樣例所示:
~~~
public class MainActivity extends FragmentActivity {
...
...
// Constants
// The authority for the sync adapter's content provider
public static final String AUTHORITY = "com.example.android.datasync.provider"
// An account type, in the form of a domain name
public static final String ACCOUNT_TYPE = "example.com";
// The account name
public static final String ACCOUNT = "dummyaccount";
// Instance fields
Account mAccount;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
// Create the dummy account
mAccount = CreateSyncAccount(this);
...
}
...
/**
* Create a new dummy account for the sync adapter
*
* @param context The application context
*/
public static Account CreateSyncAccount(Context context) {
// Create the account type and default account
Account newAccount = new Account(
ACCOUNT, ACCOUNT_TYPE);
// Get an instance of the Android account manager
AccountManager accountManager =
(AccountManager) context.getSystemService(
ACCOUNT_SERVICE);
/*
* Add the account and account type, no password or user data
* If successful, return the Account object, otherwise report an error.
*/
if (accountManager.addAccountExplicitly(newAccount, null, null))) {
/*
* If you don't set android:syncable="true" in
* in your <provider> element in the manifest,
* then call context.setIsSyncable(account, AUTHORITY, 1)
* here.
*/
} else {
/*
* The account exists or some other error occurred. Log this, report it,
* or handle it internally.
*/
}
}
...
}
~~~
### 添加Sync Adapter的元數據文件
要將你的Sync Adapter組件集成到框架中,你需要向框架提供描述組件的元數據,以及額外的標識信息。元數據指定了你為Sync Adapter所創建的賬戶類型,聲明了一個和你的應用相關聯的Content Provider Authority,對和Sync Adapter相關的一部分系統用戶接口進行控制,同時還聲明了其它同步相關的標識。在你的項目中的`/res/xml/`目錄下的一個特定的文件內聲明這一元數據,你可以為這個文件命名,不過通常來說我們將其命名為`syncadapter.xml`。
在這一文件中包含了一個XML標簽`<sync-adapter>`,它包含了下列的屬性字段:
**android:contentAuthority**
Content Provider的URI Authority。如果你在前一節課程中為你的應用創建了一個Stub Content Provider,那么請使用你在清單文件中添加在 [`<provider>`](http://developer.android.com/guide/topics/manifest/provider-element.html)標簽內的[android:authorities](http://developer.android.com/guide/topics/manifest/provider-element.html#auth)屬性值。這一屬性的更多細節在本章后續章節中有更多的介紹。
如果你正使用Sync Adapter將數據從Content Provider傳輸到服務器上,該屬性的值應該和數據的Content URI Authority保持一致。這個值也是你在清單文件中添加在[`<provider>`](http://developer.android.com/guide/topics/manifest/provider-element.html)標簽內的`android:authorities`屬性的值。
**android:accountType**
Sync Adapter框架所需要的賬戶類型。這個值必須和你所創建的驗證器元數據文件內所提供的賬戶類型一致(詳細內容可以閱讀:[創建Stub授權器](#))。這也是在上一節的代碼片段中。常量`ACCOUNT_TYPE`的值。
**配置相關屬性****android:userVisible**:該屬性設置Sync Adapter框架的賬戶類型是否可見。默認地,和賬戶類型相關聯的賬戶圖標和標簽在系統設置的賬戶選項中可以看見,所以你應該將你的Sync Adapter設置為對用戶不可見,除非你確實擁有一個賬戶類型或者域名,它們可以輕松地和你的應用相關聯。如果你將你的賬戶類型設置為不可見,你仍然可以允許用戶通過一個[Activity](# "An activity represents a single screen with a user interface.")中的用戶接口來控制你的Sync Adapter。**android:supportsUploading**:允許你將數據上傳到云。如果你的應用僅僅下載數據,那么請將該屬性設置為`false`。**android:allowParallelSyncs**:允許多個Sync Adapter組件的實例同時運行。如果你的應用支持多個用戶賬戶并且你希望多個用戶并行地傳輸數據,那么你可以使用該特性。如果你從不執行多個數據傳輸,這個選項是沒用的。**android:isAlwaysSyncable**:指明Sync Adapter框架可以在任何你指定的時間運行你的Sync Adapter。如果你希望通過代碼來控制Sync Adapter的運行時機,請將該屬性設置為`false`,然后調用[requestSync()](http://developer.android.com/reference/android/content/ContentResolver.html#requestSync(android.accounts.Account, java.lang.String, android.os.Bundle))來運行Sync Adapter。要學習更多關于運行Sync Adapter的知識,可以閱讀:[執行Sync Adapter](#)。
下面的代碼展示了應該如何通過XML配置一個使用單個虛擬賬戶,并且只執行下載的Sync Adapter:
~~~
<?xml version="1.0" encoding="utf-8"?>
<sync-adapter
xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="com.example.android.datasync.provider"
android:accountType="com.android.example.datasync"
android:userVisible="false"
android:supportsUploading="false"
android:allowParallelSyncs="false"
android:isAlwaysSyncable="true"/>
~~~
### 在Manifest清單文件中聲明Sync Adapter
一旦你將Sync Adapter組件集成到了你的應用中,你需要聲明相關的權限來使用它,并且你還需要聲明你所添加的綁定[Service](http://developer.android.com/reference/android/app/Service.html)。
由于Sync Adapter組件會運行設備與網絡之間傳輸數據的代碼,所以你需要請求使用網絡的權限。同時,你的應用還需要讀寫Sync Adapter配置信息的權限,這樣你才能通過應用中的其它組件去控制Sync Adapter。另外,你還需要一個特殊的權限,來允許你的應用使用你在[創建Stub授權器](#)中所創建的授權器組件。
要請求這些權限,將下列內容添加到應用清單文件中,并作為[`<manifest>`](http://developer.android.com/guide/topics/manifest/manifest-element.html)標簽的子標簽:
[**android.permission.INTERNET**](http://developer.android.com/reference/android/Manifest.permission.html#INTERNET)
允許Sync Adapter訪問網絡,使得它可以從設備下載和上傳數據到服務器。如果之前已經請求了該權限,那么你就不需要重復請求了。
[**android.permission.READ_SYNC_SETTINGS**](http://developer.android.com/reference/android/Manifest.permission.html#READ_SYNC_SETTINGS)
允許你的應用讀取當前的Sync Adapter配置。例如,你需要該權限來調用[getIsSyncable()](http://developer.android.com/reference/android/content/ContentResolver.html#getIsSyncable(android.accounts.Account, java.lang.String))。
[**android.permission.WRITE_SYNC_SETTINGS**](http://developer.android.com/reference/android/Manifest.permission.html#WRITE_SYNC_SETTINGS)
允許你的應用對Sync Adapter的配置進行控制。你需要這一權限來通過[addPeriodicSync()](http://developer.android.com/reference/android/content/ContentResolver.html#addPeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle, long))方法設置執行同步的時間間隔。另外,調用[requestSync()](http://developer.android.com/reference/android/content/ContentResolver.html#requestSync(android.accounts.Account, java.lang.String, android.os.Bundle))方法不需要用到該權限。更多信息可以閱讀:[執行Sync Adapter](#)。
[**android.permission.AUTHENTICATE_ACCOUNTS**](http://developer.android.com/reference/android/Manifest.permission.html#AUTHENTICATE_ACCOUNTS)
允許你使用在[創建Stub授權器](#)中所創建的驗證器組件。
下面的代碼片段展示了如何添加這些權限:
~~~
<manifest>
...
<uses-permission
android:name="android.permission.INTERNET"/>
<uses-permission
android:name="android.permission.READ_SYNC_SETTINGS"/>
<uses-permission
android:name="android.permission.WRITE_SYNC_SETTINGS"/>
<uses-permission
android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
...
</manifest>
~~~
最后,要聲明框架用來和你的Sync Adapter進行交互的綁定[Service](http://developer.android.com/reference/android/app/Service.html),添加下列的XML代碼到應用清單文件中,作為[`<application>`](http://developer.android.com/guide/topics/manifest/application-element.html)標簽的子標簽:
~~~
<service
android:name="com.example.android.datasync.SyncService"
android:exported="true"
android:process=":sync">
<intent-filter>
<action android:name="android.content.SyncAdapter"/>
</intent-filter>
<meta-data android:name="android.content.SyncAdapter"
android:resource="@xml/syncadapter" />
</service>
~~~
[`<intent-filter>`](http://developer.android.com/guide/topics/manifest/intent-filter-element.html)標簽配置了一個過濾器,它會被帶有`android.content.SyncAdapter`這一Action的Intent所觸發,該Intent一般是由系統為了運行Sync Adapter而發出的。當過濾器被觸發后,系統會啟動你所創建的綁定服務,在本例中它叫做`SyncService`。屬性[android:exported="true"](http://developer.android.com/guide/topics/manifest/service-element.html#exported)允許你應用之外的其它進程(包括系統)訪問這一[Service](http://developer.android.com/reference/android/app/Service.html)。屬性[android:process=":sync"](http://developer.android.com/guide/topics/manifest/service-element.html#proc)告訴系統應該在一個全局共享的,且名字叫做`sync`的進程內運行該[Service](http://developer.android.com/reference/android/app/Service.html)。如果你的應用中有多個Sync Adapter,那么它們可以共享該進程,這有助于減少開銷。
[`<meta-data>`](http://developer.android.com/guide/topics/manifest/meta-data-element.html)標簽提供了你之前為Sync Adapter所創建的元數據XML文件的文件名。屬性[android:name](http://developer.android.com/guide/topics/manifest/meta-data-element.html#nm)指出這一元數據是針對于Sync Adapter框架的。而[android:resource](http://developer.android.com/guide/topics/manifest/meta-data-element.html#rsrc)標簽則指定了元數據文件的名稱。
現在你已經為Sync Adapter準備好所有相關的組件了。下一節課將講授如何讓Sync Adapter框架運行你的Sync Adapter,要實現這一點,既可以通過響應一個事件的方式,也可以通過執行一個周期性任務的方式。
- 序言
- Android入門基礎:從這里開始
- 建立第一個App
- 創建Android項目
- 執行Android程序
- 建立簡單的用戶界面
- 啟動其他的Activity
- 添加ActionBar
- 建立ActionBar
- 添加Action按鈕
- 自定義ActionBar的風格
- ActionBar的覆蓋層疊
- 兼容不同的設備
- 適配不同的語言
- 適配不同的屏幕
- 適配不同的系統版本
- 管理Activity的生命周期
- 啟動與銷毀Activity
- 暫停與恢復Activity
- 停止與重啟Activity
- 重新創建Activity
- 使用Fragment建立動態的UI
- 創建一個Fragment
- 建立靈活動態的UI
- Fragments之間的交互
- 數據保存
- 保存到Preference
- 保存到文件
- 保存到數據庫
- 與其他應用的交互
- Intent的發送
- 接收Activity返回的結果
- Intent過濾
- Android分享操作
- 分享簡單的數據
- 給其他App發送簡單的數據
- 接收從其他App返回的數據
- 給ActionBar增加分享功能
- 分享文件
- 建立文件分享
- 分享文件
- 請求分享一個文件
- 獲取文件信息
- 使用NFC分享文件
- 發送文件給其他設備
- 接收其他設備的文件
- Android多媒體
- 管理音頻播放
- 控制音量與音頻播放
- 管理音頻焦點
- 兼容音頻輸出設備
- 拍照
- 簡單的拍照
- 簡單的錄像
- 控制相機硬件
- 打印
- 打印照片
- 打印HTML文檔
- 打印自定義文檔
- Android圖像與動畫
- 高效顯示Bitmap
- 高效加載大圖
- 非UI線程處理Bitmap
- 緩存Bitmap
- 管理Bitmap的內存
- 在UI上顯示Bitmap
- 使用OpenGL ES顯示圖像
- 建立OpenGL ES的環境
- 定義Shapes
- 繪制Shapes
- 運用投影與相機視圖
- 添加移動
- 響應觸摸事件
- 添加動畫
- View間漸變
- 使用ViewPager實現屏幕側滑
- 展示卡片翻轉動畫
- 縮放View
- 布局變更動畫
- Android網絡連接與云服務
- 無線連接設備
- 使得網絡服務可發現
- 使用WiFi建立P2P連接
- 使用WiFi P2P服務
- 執行網絡操作
- 連接到網絡
- 管理網絡
- 解析XML數據
- 高效下載
- 為網絡訪問更加高效而優化下載
- 最小化更新操作的影響
- 避免下載多余的數據
- 根據網絡類型改變下載模式
- 云同步
- 使用備份API
- 使用Google Cloud Messaging
- 解決云同步的保存沖突
- 使用Sync Adapter傳輸數據
- 創建Stub授權器
- 創建Stub Content Provider
- 創建Sync Adpater
- 執行Sync Adpater
- 使用Volley執行網絡數據傳輸
- 發送簡單的網絡請求
- 建立請求隊列
- 創建標準的網絡請求
- 實現自定義的網絡請求
- Android聯系人與位置信息
- Android聯系人信息
- 獲取聯系人列表
- 獲取聯系人詳情
- 使用Intents修改聯系人信息
- 顯示聯系人頭像
- Android位置信息
- 獲取最后可知位置
- 獲取位置更新
- 顯示位置地址
- 創建和監視地理圍欄
- Android可穿戴應用
- 賦予Notification可穿戴特性
- 創建Notification
- 在Notifcation中接收語音輸入
- 為Notification添加顯示頁面
- 以Stack的方式顯示Notifications
- 創建可穿戴的應用
- 創建并運行可穿戴應用
- 創建自定義的布局
- 添加語音功能
- 打包可穿戴應用
- 通過藍牙進行調試
- 創建自定義的UI
- 定義Layouts
- 創建Cards
- 創建Lists
- 創建2D-Picker
- 創建確認界面
- 退出全屏的Activity
- 發送并同步數據
- 訪問可穿戴數據層
- 同步數據單元
- 傳輸資源
- 發送與接收消息
- 處理數據層的事件
- Android TV應用
- 創建TV應用
- 創建TV應用的第一步
- 處理TV硬件部分
- 創建TV的布局文件
- 創建TV的導航欄
- 創建TV播放應用
- 創建目錄瀏覽器
- 提供一個Card視圖
- 創建詳情頁
- 顯示正在播放卡片
- 幫助用戶在TV上探索內容
- TV上的推薦內容
- 使得TV App能夠被搜索
- 使用TV應用進行搜索
- 創建TV游戲應用
- 創建TV直播應用
- TV Apps Checklist
- Android企業級應用
- Ensuring Compatibility with Managed Profiles
- Implementing App Restrictions
- Building a Work Policy Controller
- Android交互設計
- 設計高效的導航
- 規劃屏幕界面與他們之間的關系
- 為多種大小的屏幕進行規劃
- 提供向下和橫向導航
- 提供向上和歷史導航
- 綜合:設計樣例 App
- 實現高效的導航
- 使用Tabs創建Swipe視圖
- 創建抽屜導航
- 提供向上的導航
- 提供向后的導航
- 實現向下的導航
- 通知提示用戶
- 建立Notification
- 當啟動Activity時保留導航
- 更新Notification
- 使用BigView風格
- 顯示Notification進度
- 增加搜索功能
- 建立搜索界面
- 保存并搜索數據
- 保持向下兼容
- 使得你的App內容可被Google搜索
- 為App內容開啟深度鏈接
- 為索引指定App內容
- Android界面設計
- 為多屏幕設計
- 兼容不同的屏幕大小
- 兼容不同的屏幕密度
- 實現可適應的UI
- 創建自定義View
- 創建自定義的View類
- 實現自定義View的繪制
- 使得View可交互
- 優化自定義View
- 創建向后兼容的UI
- 抽象新的APIs
- 代理至新的APIs
- 使用舊的APIs實現新API的效果
- 使用版本敏感的組件
- 實現輔助功能
- 開發輔助程序
- 開發輔助服務
- 管理系統UI
- 淡化系統Bar
- 隱藏系統Bar
- 隱藏導航Bar
- 全屏沉浸式應用
- 響應UI可見性的變化
- 創建使用Material Design的應用
- 開始使用Material Design
- 使用Material的主題
- 創建Lists與Cards
- 定義Shadows與Clipping視圖
- 使用Drawables
- 自定義動畫
- 維護兼容性
- Android用戶輸入
- 使用觸摸手勢
- 檢測常用的手勢
- 跟蹤手勢移動
- Scroll手勢動畫
- 處理多觸摸手勢
- 拖拽與縮放
- 管理ViewGroup中的觸摸事件
- 處理鍵盤輸入
- 指定輸入法類型
- 處理輸入法可見性
- 兼容鍵盤導航
- 處理按鍵動作
- 兼容游戲控制器
- 處理控制器輸入動作
- 支持不同的Android系統版本
- 支持多個控制器
- Android后臺任務
- 在IntentService中執行后臺任務
- 創建IntentService
- 發送工作任務到IntentService
- 報告后臺任務執行狀態
- 使用CursorLoader在后臺加載數據
- 使用CursorLoader執行查詢任務
- 處理查詢的結果
- 管理設備的喚醒狀態
- 保持設備的喚醒
- 制定重復定時的任務
- Android性能優化
- 管理應用的內存
- 代碼性能優化建議
- 提升Layout的性能
- 優化layout的層級
- 使用include標簽重用layouts
- 按需加載視圖
- 使得ListView滑動順暢
- 優化電池壽命
- 監測電量與充電狀態
- 判斷與監測Docking狀態
- 判斷與監測網絡連接狀態
- 根據需要操作Broadcast接受者
- 多線程操作
- 在一個線程中執行一段特定的代碼
- 為多線程創建線程池
- 啟動與停止線程池中的線程
- 與UI線程通信
- 避免出現程序無響應ANR
- JNI使用指南
- 優化多核處理器(SMP)下的Android程序
- Android安全與隱私
- Security Tips
- 使用HTTPS與SSL
- 為防止SSL漏洞而更新Security
- 使用設備管理條例增強安全性
- Android測試程序
- 測試你的Activity
- 建立測試環境
- 創建與執行測試用例
- 測試UI組件
- 創建單元測試
- 創建功能測試
- 術語表