亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

【Android Developers Training】 96. 運行一個

系統 1812 0

注:本文翻譯自Google官方的Android Developers Training文檔,譯者技術一般,由于喜愛安卓而產生了翻譯的念頭,純屬個人興趣愛好。

原文鏈接: http://developer.android.com/training/sync-adapters/running-sync-adapter.html


在這系列課程中之前的一些課程中,你學習了如何創建一個封裝數據傳輸代碼的同步適配器組件,以及如何添加其它的組件以允許你將同步適配器集成到系統當中。現在已已經擁有了所有你需要的東西,來安裝包含有一個同步適配器的應用,但是沒有任何代碼是去運行同步適配器的。

你應該基于計劃任務的調度或者一些事件的間接結果。例如,你可能希望你的同步適配器運行一個定期的計劃任務,每隔一段時間或每天的一個固定的時間。或者你還希望當設備上的數據發生變化后,執行你的同步適配器。你應該避免將運行同步適配器作為用戶某個行為的直接結果,因為這樣做的話你就無法利用同步適配器框架可以按計劃調度的特性。例如,你應該在UI中避免使用刷新按鈕。

你可以有下列選項來運行你的同步適配器:

當服務器數據變更時:

運行同步適配器以響應來自服務器的消息,指明服務端的數據變化了。這一選項允許從服務器刷新數據到設備上,這一方法避免降低性能,或者由于輪詢服務器所造成的電量損耗。

當設備變化變更時:

當設備上的數據發生變化時,運行同步適配器。這一選項允許你將修改后的數據從設備發送給服務器,如果你需要保證服務器端的數據一致保持最新,那么這一選項非常有用。如果你將數據存儲于你的內容提供器,那么這一選項的實現將會非常直接。如果你使用的是一個空內容提供器,檢測數據的變化可能會比較困難。

當系統發送了一個網絡消息:

當Android系統發送了一個網絡消息來保持TCP/IP連接開啟時,運行同步適配器。這個消息是網絡框架的一個基本部分。使用這一選項是自動運行同步適配器的一個方法。可以考慮配合基于時間間隔的同步適配器一起使用。

每隔固定的時間間隔后:

在你定的時間間隔過了之后,運行同步適配器,或者在每天的固定時間運行它。

按照要求:

運行同步適配器以響應用戶的行為。然而,為了提供最佳的用戶體驗,你應該主要依賴更多自動類型的選項。使用自動化的選項,你可以節省大量的電量以及網絡資源。

本課程的后續部分會詳細介紹每個選項。


一). 當服務器數據變化時,運行同步適配器

如果你的應用從服務器傳輸數據,且服務器的數據頻繁的發生變化,你可以使用一個同步適配器通過下載數據來響應服務端數據的變化。要運行同步適配器,讓服務端向你的應用的 BroadcastReceiver 發送一條特殊的消息。要響應這條消息,可以調用 ContentResolver.requestSync() 方法,來向同步適配器框架發出信號,讓它運行你的同步適配器。

谷歌云消息( Google Cloud Messaging ,GCM)提供了你需要的服務端組件和設備端組件,來讓這一消息提供能夠運行。使用GCM激活數據傳輸比通過向服務器輪詢的方式要更加可靠,也更加有效。因為輪詢需要一個一直處于活躍狀態的 Service ,而GCM使用的 BroadcastReceiver 僅在消息到達時會激活。另外,即使沒有更新的內容,定期的輪詢也會消耗大量的電池電量,而GCM僅在需要時才會發出消息。

Note:

如果你使用GCM,通過一個到所有安裝了你的應用的設備的廣播,來激活你的同步適配器,要記住他們會在同一時間(粗略地)收到你的消息。這回導致在同一時間有多個同步適配器的實例在運行,進而導致服務器和網絡的負載過重。要避免這一情況,你應該考慮讓每個設備的同步適配器啟動的事件有所差異。

下面的代碼展示了如何運行 requestSync() 以響應一個接收到的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
      
      
        );

            ...

        }

        ...

    }

    ...

}
      
    

二). 當內容提供器的數據變化時,運行同步適配器

如果你的應用在一個內容提供器中收集數據,并且你希望當你更新提供器的時候一起更新服務器的數據,你可以配置你的同步適配器來讓它自動運行。要做到這一點,你首先應該為內容提供器注冊一個觀察器。當你的內容提供器的數據發生了變化以后,內容提供器框架會調用觀察器。在觀察器中,調用 requestSync() 來告訴框架運行你的同步適配器。

Note:

如果你使用的是一個空的內容提供器,那么你在內容提供器中沒有任何數據,并且 onChange() 方法從來沒有被調用。在這種情況下,你不得不提供你自己的機制來檢測設備數據的變化。這一機制還要負責當數據發生變化時調用 requestSync()

為了給你的內容提供器創建一個觀察器,繼承 ContentObserver 類,并且實現 onChange() 方法的幾種形式。在 onChange() 中,調用 requestSync() 來啟動同步適配器。

要注冊觀察器,將它作為參數傳遞給 registerContentObserver() 。在這個調用中,你還要傳遞一個你先要監視的內容URI。內容提供器框架會將這個監視的URI和通過 ContentResolver 方法(如 ContentResolver.insert() )所傳遞過來的修改了你的提供器的URI進行對比,如果匹配上了,那么你所實現的 ContentObserver.onChange() 將會被調用。

下面的代碼片段展示了如何定義一個 ContentObserver ,當表發生變化時調用 requestSync()

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

        ...

    }

    ...

}
      
    

三). 在一個網絡消息之后,運行同步適配器

當一個網絡連接可獲得時,Android系統會每隔幾秒發送一條消息來保持TCP/IP連接打開。這一消息也會傳遞到每個應用的 ContentResolver 中。通過調用 setSyncAutomatically() ,你可以在 ContentResolver 收到消息后,運行同步適配器。

當網絡可獲得的時候,通過調度你的同步適配器運行,來保證你的同步適配器在可以獲得網絡時都會被調度。如果不是每次數據變化時就要以數據傳輸來響應,但是又希望自己的數據會被定期地更新,那么可以用這一選項。類似地,如果你不想要給你的同步適配器配置一個定期調度,但你希望經常運行它,你也可以使用這一選項。

由于 setSyncAutomatically() 方法不會禁用 addPeriodicSync() ,你的同步適配器可能會在一小段時間內重復地被激活。如果你想要定期地運行你的同步適配器,你應該禁用 setSyncAutomatically()

下面的代碼片段向你展示如何配置你的 ContentResolver 來運行你的同步適配器,響應網絡消息:

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

        ...

    }

    ...

}
      
    

四). 定期地運行同步適配器

你可以設置一個每次運行期間的間隔時間來定期運行你的同步適配器,或者在每天的固定時間運行,或者兩者都有。定期地運行你的同步適配器可以允許你粗略地觀察你的服務器更新間隔。

同樣地,當你的服務器相對來說比較空閑時,你可以從設備更新數據,方法可以是在夜間定期調用同步適配器。大多數用戶晚上會不關機并對收集充電,所以這一方法是可行的。而且,那個時間設備不會運行其他的任務除了你的同步適配器。如果你使用這個方法的話,你需要注意每臺設備會在略微不同的時間激活數據傳輸。如果所有設備在同一時間運行你的同步適配器,那么你的服務器將很有可能負載過重。

一般來說,如果你的用戶不需要實時更新,但希望定期更新,定期運行會很有用。如果你希望在獲取實時數據和一個更小的同步適配器的效率及不過度使用用戶設備資源這兩者之間進行一個平衡,那么定期執行是一個不錯的選擇。

要定期運行你的同步適配器,調用 addPeriodicSync() 。這樣每隔一段時間,同步適配器就會運行。由于同步適配器框架會考慮其他同步適配器的執行,并嘗試最大化電池效率,間隔時間會動態做出細微調整。同時,如果網絡不可獲得,框架不會運行你的同步適配器。

注意, addPeriodicSync() 方法不會每天某個時間自動運行。要讓你的同步適配器每天某個時間內自動執行,使用一個重復計時器作為激發器。重復計時器的更多細節可以閱讀: AlarmManager 。如果你使用 setInexactRepeating() 方法來設置每天激活的時間具有一些變化,你仍然應該將不同設備的同步適配器的運行時間隨機化,使得它們的執行交錯開來。

addPeriodicSync() 方法不會禁用 setSyncAutomatically() ,所以你可能會在一小段時間內獲取多個同步執行。同樣,僅有一些同步適配器的控制標識會在 addPeriodicSync() 方法中被允許。不允許的標識在該方法的 文檔 中可以查看。

下面的代碼樣例展示了如何定期執行同步適配器:

      
        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
      
       MILLISECONDS_PER_SECOND = 1000L
      
        ;

    
      
      
        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 
      
      *
      
        

            MILLISECONDS_PER_SECOND;

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

                
      
      
        null
      
      
        ,

                SYNC_INTERVAL);

        ...

    }

    ...

}
      
    

五). 按需求執行同步適配器

運行你的同步適配器來響應一個用戶需求是運行一個同步適配器最不推薦的策略。框架是被特別設計成根據計劃運行同步適配器時最大化保留電量。在數據變化時響應一個同步適配器的同步選項應該有效地使用電量,因為電量是用來提供新數據的。

相比之下,允許用戶按照需求運行同步適配器意味著同步適配器會自己運行,這對電量和網絡來說會導致使用效率的下降。同時,向用戶提供同步,會讓用戶甚至沒有證據表明數據發生變化了以后也請求一個更新,這會導致對電量的低效率使用,一般來說,你的應用應該使用其它信號來激活一個同步更新或者定期地去做它們,而不是依賴于用戶的輸入。

然而,如果你仍然想要按照需求運行同步適配器,將同步適配器標識設置為人為運行的同步適配器,之后調用 ContentResolver.requestSync()

使用下列標識來執行按需求的數據傳輸:

SYNC_EXTRAS_MANUAL

強制執行人為的同步更新。同步適配器框架會忽略當前的設置,如被 setSyncAutomatically() 方法設置的標識。

SYNC_EXTRAS_EXPEDITED

強制同步立即執行。如果你不設置此項,系統可能會在運行同步需求之前等待一小段時間,因為它會嘗試通過將多個請求在一小段時間內調度來嘗試優化電量。

下面的代碼片段將向你展示如何調用 requestSync() 來響應一個按鈕的點擊:

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

    }
      
    

【Android Developers Training】 96. 運行一個同步適配器


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 国产精品亚洲欧美日韩一区在线 | 国产男女爽爽爽免费视频 | 视频一区二区三区在线观看 | 四虎精品视频在线永久免费观看 | 日韩国产欧美视频 | 日本一线一区二区三区免费视频 | 日韩专区中文字幕 | 日韩99在线| 97国产精品国产品国语字幕 | 国产精品久久亚洲一区二区 | 在线视频自拍 | 国内精品久久久久影院嫩草 | 欧美男女啪啪 | 亚洲成在人色婷婷 | 四虎影视在线看免费 720p | 国产精品你懂的 | 就操视频| 亚洲国产视频在线观看 | 性丰满妇女free性性性 | 国产精品福利在线 | 五月婷花| 成人精品国产亚洲欧洲 | 天堂毛片| 成年人免费在线视频 | 欧美日本一级在线播放 | 97在线影院| 久久精品国产亚洲沈樵 | 亚洲不卡视频 | 日韩中文字幕一区 | 日韩欧美在线播放 | 久热这里有精品 | 亚洲天天网综合自拍图片专区 | 久免费视频 | 一级一级一级一级毛片 | 国产精品久久大陆 | 亚洲 中文 欧美 日韩 在线人 | 欧美午夜网 | 九九在线视频 | 最近中文国语字幕在线播放视频 | 奇米影视奇米色777欧美 | 91精品欧美产品免费观看 |