<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                > 編寫:[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,要實現這一點,既可以通過響應一個事件的方式,也可以通過執行一個周期性任務的方式。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看