<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>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                > 編寫:[jdneo](https://github.com/jdneo) - 原文:[http://developer.android.com/training/sync-adapters/running-sync-adapter.html](http://developer.android.com/training/sync-adapters/running-sync-adapter.html) 在本節課之前,你已經學習了如何創建一個封裝了數據傳輸代碼的Sync Adapter組件,以及如何添加其它的組件,使得你可以將Sync Adapter集成到系統當中。現在你已經擁有了所有部件,來安裝一個包含有Sync Adapter的應用了,但是這里還沒有任何代碼是負責去運行Sync Adapter的。 執行Sync Adapter的時機,一般應該基于某個計劃任務或者一些事件的間接結果。例如,你可能希望你的Sync Adapter以一個定期計劃任務的形式運行(比如每隔一段時間或者在每天的一個固定時間運行)。或者你也可能希望當設備上的數據發生變化后,執行你的Sync Adapter。你應該避免將運行Sync Adapter作為用戶某個行為的直接結果,因為這樣做的話你就無法利用Sync Adapter框架可以按計劃調度的特性。例如,你應該在UI中避免使用刷新按鈕。 下列情況可以作為運行Sync Adapter的時機: **當服務端數據變更時:** 當服務端發送消息告知服務端數據發生變化時,運行Sync Adapter以響應這一來自服務端的消息。這一選項允許從服務器更新數據到設備上,該方法可以避免由于輪詢服務器所造成的執行效率下降,或者電量損耗。 **當設備的數據變更時:** 當設備上的數據發生變化時,運行Sync Adapter。這一選項允許你將修改后的數據從設備發送給服務器,如果你需要保證服務器端一直擁有設備上最新的數據,那么這一選項非常有用。如果你將數據存儲于你的Content Provider,那么這一選項的實現將會非常直接。如果你使用的是一個Stub Content Provider,檢測數據的變化可能會比較困難。 **當系統發送了一個網絡消息:** 當Android系統發送了一個網絡消息來保持TCP/IP連接開啟時,運行Sync Adapter。這個消息是網絡框架(Networking Framework)的一個基本部分。可以將這一選項作為自動運行Sync Adapter的一個方法。另外還可以考慮將它和基于時間間隔運行Sync Adapter的策略結合起來使用。 **每隔固定的時間間隔后:** 可以每隔一段你指定的時間間隔后,運行Sync Adapter,或者在每天的固定時間運行它。 **根據需求:** 運行Sync Adapter以響應用戶的行為。然而,為了提供最佳的用戶體驗,你應該主要依賴那些更加自動式的選項。使用自動式的選項,你可以節省大量的電量以及網絡資源。 本課程的后續部分會詳細介紹每個選項。 ### 當服務器數據變化時,運行Sync Adapter 如果你的應用從服務器傳輸數據,且服務器的數據會頻繁地發生變化,你可以使用一個Sync Adapter通過下載數據來響應服務端數據的改變。要運行Sync Adapter,我們需要讓服務端向應用的[BroadcastReceiver](http://developer.android.com/reference/android/content/BroadcastReceiver.html)發送一條特殊的消息。為了響應這條消息,可以調用[ContentResolver.requestSync()](http://developer.android.com/reference/android/content/ContentResolver.html#requestSync(android.accounts.Account, java.lang.String, android.os.Bundle))方法,向Sync Adapter框架發出信號,讓它運行你的Sync Adapter。 谷歌云消息([Google Cloud Messaging](http://developer.android.com/google/gcm/index.html),GCM)提供了你需要的服務端組件和設備端組件,來讓上述消息系統能夠運行。使用GCM觸發數據傳輸比通過向服務器輪詢的方式要更加可靠,也更加有效。因為輪詢需要一個一直處于活躍狀態的[Service](http://developer.android.com/reference/android/app/Service.html),而GCM使用的[BroadcastReceiver](http://developer.android.com/reference/android/content/BroadcastReceiver.html)僅在消息到達時會被激活。另外,即使沒有更新的內容,定期的輪詢也會消耗大量的電池電量,而GCM僅在需要時才會發出消息。 > **Note:**如果你使用GCM,將廣播消息發送到所有安裝了你的應用的設備,來激活你的Sync Adapter,要記住他們會在同一時間(粗略地)收到你的消息。這會導致在同一時段內有多個Sync Adapter的實例在運行,進而導致服務器和網絡的負載過重。要避免這一情況,你應該考慮為不同的設備設定不同的Sync Adapter延遲啟動時間。 下面的代碼展示了如何通過[requestSync()](http://developer.android.com/reference/android/content/ContentResolver.html#requestSync(android.accounts.Account, java.lang.String, android.os.Bundle))響應一個接收到的GCM消息: ~~~ public class GcmBroadcastReceiver extends BroadcastReceiver { ... // Constants // Content provider authority public static final String AUTHORITY = "com.example.android.datasync.provider" // Account type public static final String ACCOUNT_TYPE = "com.example.android.datasync"; // Account public static final String ACCOUNT = "default_account"; // Incoming Intent key for extended data public static final String KEY_SYNC_REQUEST = "com.example.android.datasync.KEY_SYNC_REQUEST"; ... @Override public void onReceive(Context context, Intent intent) { // Get a GCM object instance GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context); // Get the type of GCM message String messageType = gcm.getMessageType(intent); /* * Test the message type and examine the message contents. * Since GCM is a general-purpose messaging system, you * may receive normal messages that don't require a sync * adapter run. * The following code tests for a a boolean flag indicating * that the message is requesting a transfer from the device. */ if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType) && intent.getBooleanExtra(KEY_SYNC_REQUEST)) { /* * Signal the framework to run your sync adapter. Assume that * app initialization has already created the account. */ ContentResolver.requestSync(ACCOUNT, AUTHORITY, null); ... } ... } ... } ~~~ ### 當Content Provider的數據變化時,運行Sync Adapter 如果你的應用在一個Content Provider中收集數據,并且你希望當你更新了Content Provider的時候,同時更新服務器的數據,你可以配置你的Sync Adapter來讓它自動運行。要做到這一點,你首先應該為Content Provider注冊一個Observer。當Content Provider的數據發生了變化之后,Content Provider框架會調用Observer。在Observer中,調用[requestSync()](http://developer.android.com/reference/android/content/ContentResolver.html#requestSync(android.accounts.Account, java.lang.String, android.os.Bundle))來告訴框架現在應該運行你的Sync Adapter了。 > **Note:**如果你使用的是一個Stub Content Provider,那么你不會在Content Provider中有任何數據,并且[onChange()](http://developer.android.com/reference/android/database/ContentObserver.html#onChange(boolean))方法也從來不會被調用。在這種情況下,你不得不提供自己的某種機制來檢測設備數據的變化。這一機制還要負責在數據發生變化時調用[requestSync()](http://developer.android.com/reference/android/content/ContentResolver.html#requestSync(android.accounts.Account, java.lang.String, android.os.Bundle))。 為了給你的Content Provider創建一個Observer,繼承[ContentObserver](http://developer.android.com/reference/android/database/ContentObserver.html)類,并且實現[onChange()](http://developer.android.com/reference/android/database/ContentObserver.html#onChange(boolean))方法的兩種形式。在[onChange()](http://developer.android.com/reference/android/database/ContentObserver.html#onChange(boolean))中,調用[requestSync()](http://developer.android.com/reference/android/content/ContentResolver.html#requestSync(android.accounts.Account, java.lang.String, android.os.Bundle))來啟動Sync Adapter。 要注冊Observer,需要將它作為參數傳遞給[registerContentObserver()](http://developer.android.com/reference/android/content/ContentResolver.html#registerContentObserver(android.net.Uri, boolean, android.database.ContentObserver))。在該方法中,你還要傳遞一個你想要監視的Content URI。Content Provider框架會將這個需要監視的URI與其它一些Content URIs進行比較,這些其它的Content URIs來自于[ContentResolver](http://developer.android.com/reference/android/content/ContentResolver.html)中那些可以修改Provider的方法(如[ContentResolver.insert()](http://developer.android.com/reference/android/content/ContentResolver.html#insert(android.net.Uri, android.content.ContentValues)))所傳入的參數,如果出現了變化,那么你所實現的[ContentObserver.onChange()](http://developer.android.com/reference/android/database/ContentObserver.html#onChange(boolean))將會被調用。 下面的代碼片段展示了如何定義一個[ContentObserver](http://developer.android.com/reference/android/database/ContentObserver.html),它在表數據發生變化后調用[requestSync()](http://developer.android.com/reference/android/content/ContentResolver.html#requestSync(android.accounts.Account, java.lang.String, android.os.Bundle)): ~~~ public class MainActivity extends FragmentActivity { ... // Constants // Content provider scheme public static final String SCHEME = "content://"; // Content provider authority public static final String AUTHORITY = "com.example.android.datasync.provider"; // Path for the content provider table public static final String TABLE_PATH = "data_table"; // Account public static final String ACCOUNT = "default_account"; // Global variables // A content URI for the content provider's data table Uri mUri; // A content resolver for accessing the provider ContentResolver mResolver; ... public class TableObserver extends ContentObserver { /* * Define a method that's called when data in the * observed content provider changes. * This method signature is provided for compatibility with * older platforms. */ @Override public void onChange(boolean selfChange) { /* * Invoke the method signature available as of * Android platform version 4.1, with a null URI. */ onChange(selfChange, null); } /* * Define a method that's called when data in the * observed content provider changes. */ @Override public void onChange(boolean selfChange, Uri changeUri) { /* * Ask the framework to run your sync adapter. * To maintain backward compatibility, assume that * changeUri is null. ContentResolver.requestSync(ACCOUNT, AUTHORITY, null); } ... } ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... // Get the content resolver object for your app mResolver = getContentResolver(); // Construct a URI that points to the content provider data table mUri = new Uri.Builder() .scheme(SCHEME) .authority(AUTHORITY) .path(TABLE_PATH) .build(); /* * Create a content observer object. * Its code does not mutate the provider, so set * selfChange to "false" */ TableObserver observer = new TableObserver(false); /* * Register the observer for the data table. The table's path * and any of its subpaths trigger the observer. */ mResolver.registerContentObserver(mUri, true, observer); ... } ... } ~~~ ### 在一個網絡消息之后,運行Sync Adapter 當可以獲得一個網絡連接時,Android系統會每隔幾秒發送一條消息來保持TCP/IP連接處于開啟狀態。這一消息也會傳遞到每個應用的[ContentResolver](http://developer.android.com/reference/android/content/ContentResolver.html)中。通過調用[setSyncAutomatically()](http://developer.android.com/reference/android/content/ContentResolver.html#setSyncAutomatically(android.accounts.Account, java.lang.String, boolean)),你可以在[ContentResolver](http://developer.android.com/reference/android/content/ContentResolver.html)收到消息后,運行Sync Adapter。 每當網絡消息被發送后運行你的Sync Adapter,通過這樣的調度方式可以保證每次運行Sync Adapter時都可以訪問網絡。如果不是每次數據變化時就要以數據傳輸來響應,但是又希望自己的數據會被定期地更新,那么你可以用這一選項。類似地,如果你不想要定期執行你的Sync Adapter,但你希望經常運行它,你也可以使用這一選項。 由于[setSyncAutomatically()](http://developer.android.com/reference/android/content/ContentResolver.html#setSyncAutomatically(android.accounts.Account, java.lang.String, boolean))方法不會禁用[addPeriodicSync()](http://developer.android.com/reference/android/content/ContentResolver.html#addPeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle, long)),所以你的Sync Adapter可能會在一小段時間內重復地被觸發激活。如果你想要定期地運行你的Sync Adapter,應該禁用[setSyncAutomatically()](http://developer.android.com/reference/android/content/ContentResolver.html#setSyncAutomatically(android.accounts.Account, java.lang.String, boolean))。 下面的代碼片段向你展示如何配置你的[ContentResolver](http://developer.android.com/reference/android/content/ContentResolver.html),利用它來響應網絡消息,從而運行你的Sync Adapter,: ~~~ public class MainActivity extends FragmentActivity { ... // Constants // Content provider authority public static final String AUTHORITY = "com.example.android.datasync.provider"; // Account public static final String ACCOUNT = "default_account"; // Global variables // A content resolver for accessing the provider ContentResolver mResolver; ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... // Get the content resolver for your app mResolver = getContentResolver(); // Turn on automatic syncing for the default account and authority mResolver.setSyncAutomatically(ACCOUNT, AUTHORITY, true); ... } ... } ~~~ ### 定期地運行Sync Adapter 你可以設置一個每次運行之間的時間間隔來定期運行你的Sync Adapter,或者在每天的固定時間運行它,還可以兩種策略同時使用。定期地運行你的Sync Adapter可以讓你與服務器的更新間隔大致保持一致。 同樣地,當你的服務器相對來說比較空閑時,你可以通過在夜間定期調用Sync Adapter,把設備上的數據上傳到服務器。大多數用戶在晚上不會關機,并為手機充電,所以這一方法是可行的。而且,通常來說,設備不會在深夜運行除了你的Sync Adapter之外的其他的任務。然而,如果你使用這個方法的話,你需要注意讓每臺設備在略微不同的時間觸發數據傳輸。如果所有設備在同一時間運行你的Sync Adapter,那么你的服務器和移動運營商的網絡將很有可能負載過重。 一般來說,當你的用戶不需要實時更新,而希望定期更新時,使用定期運行的策咯會很有用。如果你希望在數據的實時性和Sync Adapter的資源消耗之間進行一個平衡,那么定期執行是一個不錯的選擇。 要定期運行你的Sync Adapter,調用[addPeriodicSync()](http://developer.android.com/reference/android/content/ContentResolver.html#addPeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle, long))。這樣每隔一段時間,Sync Adapter就會運行。由于Sync Adapter框架會考慮其他Sync Adapter的執行,并嘗試最大化電池效率,所以間隔時間會動態地進行細微調整。同時,如果當前無法獲得網絡連接,框架不會運行你的Sync Adapter。 注意,[addPeriodicSync()](http://developer.android.com/reference/android/content/ContentResolver.html#addPeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle, long))方法不會讓Sync Adapter每天在某個時間自動運行。要讓你的Sync Adapter在每天的某個時刻左右自動執行,可以使用一個重復計時器作為觸發器。重復計時器的更多細節可以閱讀:[AlarmManager](http://developer.android.com/reference/android/app/AlarmManager.html)。如果你使用[setInexactRepeating()](http://developer.android.com/reference/android/app/AlarmManager.html#setInexactRepeating(int, long, long, android.app.PendingIntent))方法設置了一個每天的觸發時刻會有粗略變化的觸發器,你仍然應該將不同設備的Sync Adapter的運行時間隨機化,使得它們的執行交錯開來。 [addPeriodicSync()](http://developer.android.com/reference/android/content/ContentResolver.html#addPeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle, long))方法不會禁用[setSyncAutomatically()](http://developer.android.com/reference/android/content/ContentResolver.html#setSyncAutomatically(android.accounts.Account, java.lang.String, boolean)),所以你可能會在一小段時間內產生多個Sync Adapter的運行實例。另外,僅有一部分Sync Adapter的控制標識可以在調用[addPeriodicSync()](http://developer.android.com/reference/android/content/ContentResolver.html#addPeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle, long))時使用。不被允許的標識在該方法的[文檔](http://developer.android.com/reference/android/content/ContentResolver.html#addPeriodicSync(android.accounts.Account,%20java.lang.String,%20android.os.Bundle,%20long))中可以查看。 下面的代碼樣例展示了如何定期執行Sync Adapter: ~~~ public class MainActivity extends FragmentActivity { ... // Constants // Content provider authority public static final String AUTHORITY = "com.example.android.datasync.provider"; // Account public static final String ACCOUNT = "default_account"; // Sync interval constants public static final long SECONDS_PER_MINUTE = 60L; public static final long SYNC_INTERVAL_IN_MINUTES = 60L; public static final long SYNC_INTERVAL = SYNC_INTERVAL_IN_MINUTES * SECONDS_PER_MINUTE; // Global variables // A content resolver for accessing the provider ContentResolver mResolver; ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... // Get the content resolver for your app mResolver = getContentResolver(); /* * Turn on periodic syncing */ ContentResolver.addPeriodicSync( ACCOUNT, AUTHORITY, Bundle.EMPTY, SYNC_INTERVAL); ... } ... } ~~~ ### 按需求執行Sync Adapter 以響應用戶請求的方式運行Sync Adapter是最不推薦的策略。要知道,該框架是被特別設計的,它可以讓Sync Adapter在根據某個調度規則運行時,能夠盡量最高效地使用手機電量。顯然,在數據改變的時候執行同步可以更有效的使用手機電量,因為電量都消耗在了更新新的數據上。 相比之下,允許用戶按照自己的需求運行Sync Adapter意味著Sync Adapter會自己運行,這將無法有效地使用電量和網絡資源。如果根據需求執行同步,會誘導用戶即便沒有證據表明數據發生了變化也請求一個更新,這些無用的更新會導致對電量的低效率使用。一般來說,你的應用應該使用其它信號來觸發一個同步更新或者讓它們定期地去執行,而不是依賴于用戶的輸入。 不過,如果你仍然想要按照需求運行Sync Adapter,可以將Sync Adapter的配置標識設置為手動執行,之后調用[ContentResolver.requestSync()](http://developer.android.com/reference/android/content/ContentResolver.html#requestSync(android.accounts.Account, java.lang.String, android.os.Bundle))來觸發一次更新。 通過下列標識來執行按需求的數據傳輸: [**SYNC_EXTRAS_MANUAL**](http://developer.android.com/reference/android/content/ContentResolver.html#SYNC_EXTRAS_MANUAL) 強制執行手動的同步更新。Sync Adapter框架會忽略當前的設置,比如通過[setSyncAutomatically()](http://developer.android.com/reference/android/content/ContentResolver.html#setSyncAutomatically(android.accounts.Account, java.lang.String, boolean))方法設置的標識。 [**SYNC_EXTRAS_EXPEDITED**](http://developer.android.com/reference/android/content/ContentResolver.html#SYNC_EXTRAS_EXPEDITED) 強制同步立即執行。如果你不設置此項,系統可能會在運行同步請求之前等待一小段時間,因為它會嘗試將一小段時間內的多個請求集中在一起調度,目的是為了優化電量的使用。 下面的代碼片段將向你展示如何調用[requestSync()](http://developer.android.com/reference/android/content/ContentResolver.html#requestSync(android.accounts.Account, java.lang.String, android.os.Bundle))來響應一個按鈕點擊事件: ~~~ public class MainActivity extends FragmentActivity { ... // Constants // Content provider authority public static final String AUTHORITY = "com.example.android.datasync.provider" // Account type public static final String ACCOUNT_TYPE = "com.example.android.datasync"; // Account public static final String ACCOUNT = "default_account"; // Instance fields Account mAccount; ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... /* * Create the dummy account. The code for CreateSyncAccount * is listed in the lesson Creating a Sync Adapter */ mAccount = CreateSyncAccount(this); ... } /** * Respond to a button click by calling requestSync(). This is an * asynchronous operation. * * This method is attached to the refresh button in the layout * XML file * * @param v The View associated with the method call, * in this case a Button */ public void onRefreshButtonClick(View v) { ... // Pass the settings flags by inserting them in a bundle Bundle settingsBundle = new Bundle(); settingsBundle.putBoolean( ContentResolver.SYNC_EXTRAS_MANUAL, true); settingsBundle.putBoolean( ContentResolver.SYNC_EXTRAS_EXPEDITED, true); /* * Request the sync for the default account, authority, and * manual sync settings */ ContentResolver.requestSync(mAccount, AUTHORITY, settingsBundle); } ~~~
                  <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>

                              哎呀哎呀视频在线观看