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

【Android Developers Training】 91. 解決云儲

系統(tǒng) 1813 0

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

原文鏈接: http://developer.android.com/training/cloudsave/conflict-res.html


在云存儲中保存和加載過程是很直接的:它只是將用于數(shù)據(jù)和byte數(shù)組之間的序列化轉(zhuǎn)換,并將這些數(shù)組存儲在云端。然而, 當你的用戶有多個設(shè)備,并且兩個以上的設(shè)備嘗試將它們的數(shù)據(jù)存儲在云端時,這一保存可能會引起沖突,因此你必須決定應(yīng)該如何處理。你在云端存儲的數(shù)據(jù)結(jié)構(gòu)在很大程度上決定了你的沖突解決方案的魯棒性,所以小心地設(shè)計你的數(shù)據(jù),使得你的沖突檢測解決方案邏輯可以正確地處理每一種情況。

本片文章從描述一些有缺陷的方法入手,并解釋他們?yōu)楹尉哂腥毕荨V蟪尸F(xiàn)一個解決方案來避免沖突。用于討論的例子關(guān)注于游戲,但解決問題的宗旨是可以適用于任何將數(shù)據(jù)存儲于云端的應(yīng)用的。


一). 沖突時獲得通知

OnStateLoadedListener 方法負責從 Google 服務(wù)器下載應(yīng)用的狀態(tài)數(shù)據(jù)。回調(diào)函數(shù) OnStateLoadedListener.onStateConflict 為你的應(yīng)用在本地狀態(tài)和云端存儲的狀態(tài)發(fā)生沖突時, 提供了一個解決機制:

      
        @Override


      
      
        public
      
      
        void
      
       onStateConflict(
      
        int
      
      
         stateKey, String resolvedVersion,

    
      
      
        byte
      
      [] localData, 
      
        byte
      
      
        [] serverData) {

    
      
      
        //
      
      
         resolve conflict, then call mAppStateClient.resolveConflict()
      
      
         ...

}
      
    

此時你的應(yīng)用必須決定要保留哪一個數(shù)據(jù),或者它自己提交一個新的數(shù)據(jù)來表示合并后的數(shù)據(jù)狀態(tài)(譯者注:是不是有點像git/svn呢?),解決沖突的邏輯由你來實現(xiàn)。

我們必須要意識到云存儲服務(wù)是在后臺執(zhí)行同步的。所以你應(yīng)該確保你的應(yīng)用能夠在你創(chuàng)建這一數(shù)據(jù)的context之外接收回調(diào)。特別地,如果Google Play服務(wù)應(yīng)用在后臺檢測到了一個沖突,該回調(diào)函數(shù)可以在你下一次加載數(shù)據(jù)時被調(diào)用,而不是下一次用戶啟動該應(yīng)用時。

因此,你的云存儲代碼和沖突解決代碼的設(shè)計必須是和當前context無關(guān)的:即給兩個沖突的數(shù)據(jù),你必須僅通過數(shù)據(jù)集中獲取的數(shù)據(jù)區(qū)解決沖突,而不依賴于任何其它外部環(huán)境。


二). 處理簡單地情況

下面列舉一些沖突解決的簡單例子。對于很多應(yīng)用而言,用這些策略或者其變體就足夠解決大多數(shù)問題了:

新的比舊的更有效 :在一些情況下,新的數(shù)據(jù)總是替代老數(shù)據(jù)。例如,如果數(shù)據(jù)代表了用戶選擇角色的衣服顏色,那么最近的新的選擇就應(yīng)該覆蓋老的選擇。在這種情況下,你可能會選擇在云存儲數(shù)據(jù)中存儲時間戳。當處理這些沖突時,選擇時間戳最新的數(shù)據(jù)(記住要選擇一個可靠的時鐘,并注意對不同時區(qū)的處理)。

有一個數(shù)據(jù)集中的數(shù)據(jù)比其它的更好 :在一些情況下,我們是可以有方法在若干數(shù)據(jù)集中選取一個最好的。例如,如果數(shù)據(jù)代表了玩家在賽車比賽中的最佳時間,那么顯然,在沖突發(fā)生時,你應(yīng)該保留成績最好的那個數(shù)據(jù)。

進行合并 :有可能通過計算兩個數(shù)據(jù)集的合并版本來解決沖突。例如,如果你的數(shù)據(jù)代表了用戶解鎖關(guān)卡的進度,那么解決的數(shù)據(jù)就是沖突集的并集。通過這個方法,用戶不會丟失任何他的游戲進度。這里的 例子 使用了這一操作的一個變形。


三). 為更復(fù)雜的情況設(shè)計一個策略

一個更復(fù)雜的情況是當你的游戲允許玩家收集可以互換的東西時(比如金幣或者經(jīng)驗點數(shù)),我們來假想一個游戲,叫做“金幣跑酷”,一個無限跑步的角色其目標是不斷地收集金幣是自己變的富有。每個收集到的金幣都會加入到玩家的儲蓄罐中。

下面的章節(jié)將展示三種在多個設(shè)備間解決沖突的方案:有兩個聽上去很不錯,可惜最終還是不能適用于所有的場景,最后一個解決方案可以解決多個設(shè)備間的沖突。

第一個嘗試:只保存總數(shù)

首先,這個問題看上去像是說:云存儲的數(shù)據(jù)只要存儲金幣的數(shù)量就行了。但是如果就只有這些數(shù)據(jù)是可用的,那么解決沖突的方案將會嚴重受到限制。此時最佳的方案就是在沖突發(fā)生時存儲最大數(shù)值得數(shù)據(jù)。

想一下表一中所展現(xiàn)的場景。假設(shè)玩家一開始有20枚硬幣,然后再設(shè)備A上收集了10個,在設(shè)備B上收集了15個。然后設(shè)備B將數(shù)據(jù)存儲到了云端。當設(shè)備A嘗試去存儲的時候,沖突發(fā)生了。“只存儲總數(shù)”的沖突解決方案會存儲35作為這一數(shù)據(jù)的值(兩數(shù)之間最大的)

表1. 值保存最大的數(shù)(不佳的策略)

事件 設(shè)備A的數(shù)據(jù) 設(shè)備B的數(shù)據(jù) 云端的數(shù)據(jù) 實際的總數(shù)
開始階段 20 20 20 20
玩家在A設(shè)備上收集了10個硬幣 30 20 20 30
玩家在B設(shè)備上收集了15個硬幣 30 35 20 45
設(shè)備B將數(shù)據(jù)存儲至云端 30 35 35 45

設(shè)備A嘗試將數(shù)據(jù)存儲至云端

發(fā)生沖突

30 35 35 45
設(shè)備A通過選擇兩數(shù)中最大的數(shù)來解決沖突 35 35 35 45

這一策略會失敗——玩家的金幣數(shù)從20變成35,但實際上玩家總共收集了25個硬幣(A設(shè)備10個,B設(shè)備15個)。所以有10個硬幣丟失了。只在云端存儲硬幣的總數(shù)是不足以實現(xiàn)一個魯棒的沖突解決算法的。

第二個嘗試:存儲總數(shù)和變化值

另一個方法是在存儲數(shù)據(jù)中包括一些額外的數(shù)據(jù):自上次提交后硬幣增加的數(shù)量(delta)。在這一方法中,存儲的數(shù)據(jù)可以用一個二元組來表示(T, d),其中T是硬幣的總數(shù),而d是硬幣增加的數(shù)量。

在這個結(jié)構(gòu)中,你的沖突檢測算法在魯棒性上有更大的提升空間,如下將要講的那樣。但是這個方法還是無法給出一個可靠的玩家最終的狀態(tài)。

下面是包含delta的沖突解決算法過程:

  • 本地數(shù)據(jù): (T, d)
  • 云端數(shù)據(jù): (T', d')
  • 解決后的數(shù)據(jù): (T'+d, d)

例如,當你在本地狀態(tài)( T, d )和云端狀態(tài)( T', d )之間發(fā)生了沖突時,你可以將它們合并成 T'+d, d )。意味著你從本地拿出delta數(shù)據(jù),并將它和云端的數(shù)據(jù)結(jié)合起來,乍一看,這種方法可以很好的計量多個設(shè)備所收集的金幣。

看上去很可靠的方法,但這個方法在動態(tài)移動環(huán)境中難以適用:

  • 用戶可能在設(shè)備不在線時存儲數(shù)據(jù)。這些改變會以隊列形式等待手機聯(lián)網(wǎng)后提交。
  • 這個方法的同步機制是用最新的變化覆蓋掉任何之前的變化。換句話說,第二次寫入的變化會提交到云端(當設(shè)備聯(lián)網(wǎng)了以后),而第一次寫入的變化就被忽略了。

為了進一步說明,我們考慮一下表2所列的場景。在表2的一系列操作后,云端的狀態(tài)將是(130, +5),之后最終沖突解決后的狀態(tài)時(140, +10)。這是不正確的,因為從總體上而言,用戶一共在A上收集了110枚硬幣而在B上收集了120枚硬幣。總數(shù)應(yīng)該為250。

表2. “總數(shù)+增量”策略的失敗案例

事件? 設(shè)備A的數(shù)據(jù)? 設(shè)備B的數(shù)據(jù)? 云端的數(shù)據(jù)? 實際的數(shù)據(jù)?
?開始階段 ?(20, x) ?(20, x) (20, x)? 20?
?玩家在A設(shè)備上收集了100個硬幣 ?(120, +100) ?(20, x) (20, x)? 120?
?玩家在A設(shè)備上又收集了10個硬幣 ? (130, +10) ?(20, x) (20, x)
130?
?玩家在B設(shè)備上收集了115個硬幣 (130, +10) (125, +115)
(20, x) 245?
?玩家在B設(shè)備上又收集了5個硬幣 (130, +10) (130, +5)? (20, x)
250?
?設(shè)備B將數(shù)據(jù)存儲至云端 (130, +10) (130, +5)? (130, +5) 250?
?

設(shè)備A嘗試將數(shù)據(jù)存儲至云端

發(fā)生沖突

(130, +10) ? (130, +5)? (130, +5)? 250?
?設(shè)備A通過將本地的增量和云端的總數(shù)相加來解決沖突 ?(140, +10) (130, +5)? (140, +10) ? 250?

注:x代表與該場景無關(guān)的數(shù)據(jù)

你可能會嘗試在每次保存后不重置增量數(shù)據(jù)來解決此問題,這樣的話在每個設(shè)備上的第二次存儲所收集到的硬幣將不會產(chǎn)生問題。這樣的話設(shè)備A在第二次本地存儲完成后,數(shù)據(jù)將是( 130, +110 )而不是( 130, +10 )。然而,這樣做的話就會發(fā)生如表3所述的情況:

表3. 算法改進后的失敗案例

事件 設(shè)備A的數(shù)據(jù) 設(shè)備B的數(shù)據(jù)? 云端的數(shù)據(jù) 實際的數(shù)據(jù)
?開始階段 (20, x) (20, x) (20, x) 20
?玩家在A設(shè)備上收集了100個硬幣 (120, +100) (20, x) (20, x) 120
設(shè)備A將狀態(tài)存儲到云端 (120, +100) (20, x) (120, +100) 120
?玩家在A設(shè)備上又收集了10個硬幣 (130, +110) (20, x) (120, +100) 130
?玩家在B設(shè)備上收集了1個硬幣 (130, +110) (21, +1) (120, +100) 131

?設(shè)備B嘗試向云端存儲數(shù)據(jù)

發(fā)生沖突

(130, +110) (21, +1) (120, +100) 131
?設(shè)備B通過將本地的增量和云端的總數(shù)相加來解決沖突 (130, +110) (121, +1) (121, +1) 131
?

設(shè)備A嘗試將數(shù)據(jù)存儲至云端

發(fā)生沖突

(130, +110) (121, +1) (121, +1) 131
?設(shè)備A通過將本地的增量和云端的總數(shù)相加來解決沖突 (231, +110) (121, +1) (231, +110) 131

注:x代表與該場景無關(guān)的數(shù)據(jù)

現(xiàn)在你碰到了另一個問題:你給予了玩家過多的硬幣。這個玩家拿到了211枚硬幣,但實際上他只收集了111枚。

解決辦法:

我們分析之前的幾次嘗試,我們發(fā)現(xiàn)這些策略都沒有這樣一個能力:知曉哪些硬幣已經(jīng)計數(shù)了,哪些硬幣沒有被計數(shù),尤其是當多個設(shè)備連續(xù)提交的時候,算法會出現(xiàn)混亂。

該問題的解決辦法將你云端的存儲結(jié)構(gòu)改為字段,使用字符串+整形的鍵值對。每一個鍵值對都會代表一個包含硬幣的“委托”,而總數(shù)就應(yīng)該是將所有值加起來。這一設(shè)計的宗旨是每個設(shè)備有它自己的委托,并且只有設(shè)備自己可以吧硬幣放到其委托中。

字典的結(jié)構(gòu)是: (A:a, B:b, C:c, ...) ,其中a代表了委托A所擁有的硬幣,b是委托B所擁有的硬幣,以此類推。

這樣的話,新的沖突解決策略算法將如下所示:

本地數(shù)據(jù): (A:a, B:b, C:c, ...)

云端數(shù)據(jù): (A:a', B:b', C:c', ...)

解決后的數(shù)據(jù) (A: max (a,a'), B: max (b,b'), C: max (c,c'), ...)

例如,如果本地數(shù)據(jù)是 (A:20, B:4, C:7) 并且云端數(shù)據(jù)是 (B:10, C:2, D:14) ,這樣的話解決沖突后的數(shù)據(jù)將會是 (A:20, B:10, C:7, D:14) 。注意,你應(yīng)用的沖突解決邏輯會根據(jù)具體的場景可能有所差異。比如,有一些應(yīng)用你可能希望挑選最小的值。

為了測試新的算法,將它應(yīng)用于任何一個之前提到過的場景。你將會發(fā)現(xiàn)它都能取得正確地結(jié)果。

表4闡述了這一點,它基于表3的場景。注意下面所列的:

在初始狀態(tài),玩家有20枚硬幣。此數(shù)值在所有設(shè)備和云端都是正確的,我們用(X:20)這一元祖代表它,其中X我們不用太多關(guān)心,我們不去追求這個初始化的數(shù)據(jù)是哪兒來的。

當玩家在設(shè)備A上收集了100枚硬幣,這一變化會作為一個元組保存到云端。它的值是100是因為這就是玩家在設(shè)備A上收集的硬幣數(shù)量。在這一過程中,沒有要執(zhí)行數(shù)據(jù)的計算——設(shè)備A僅僅是將玩家所收集的數(shù)據(jù)匯報給了云端。

每一個新的硬幣提交會打包成一個于設(shè)備關(guān)聯(lián)的元組并保存到云端。例如,假設(shè)玩家又在設(shè)備A上收集了100枚硬幣,那么元組的值被更新為110。

最終的結(jié)果就是,應(yīng)用知道了玩家在每個設(shè)備上收集硬幣的總數(shù)。這樣它就能輕易地計算總數(shù)了。

表4. 鍵值對策略的成功應(yīng)用案例

事件 設(shè)備A的數(shù)據(jù) 設(shè)備B的數(shù)據(jù) 云端的數(shù)據(jù) 實際的數(shù)據(jù)
開始階段 (X:20, x) (X:20, x) (X:20, x) 20
玩家在A設(shè)備上收集了100個硬幣 (X:20, A:100) (X:20) (X:20) 120
設(shè)備A將狀態(tài)存儲到云端 (X:20, A:100) (X:20) (X:20, A:100) 120
玩家在A設(shè)備上又收集了10個硬幣 (X:20, A:110) (X:20) (X:20, A:100) 130
玩家在B設(shè)備上收集了1個硬幣 (X:20, A:110) (X:20, B:1) (X:20, A:100) 131

設(shè)備B嘗試向云端存儲數(shù)據(jù)

發(fā)生沖突

(X:20, A:110) (X:20, B:1) (X:20, A:100) 131
設(shè)備B解決沖突 (X:20, A:110) (X:20, A:100, B:1) (X:20, A:100, B:1) 131

設(shè)備A嘗試將數(shù)據(jù)存儲至云端

發(fā)生沖突

(X:20, A:110) (X:20, A:100, B:1) (X:20, A:100, B:1) 131
設(shè)備A解決沖突 (X:20, A:110, B:1) (X:20, A:100, B:1) (X:20, A:110, B:1)?
total 131
131

四). 清除你的數(shù)據(jù)

在云端存儲數(shù)據(jù)的大小是由限制的,所以在后續(xù)的論述中,我們將會關(guān)注與如何避免創(chuàng)建過大的詞典。一開始,看上去每個設(shè)備只會有一個詞典字段,即使是非常激進的用戶也不太會擁有上千條字段。然而, 獲取設(shè)備ID的方法很難,并且我們認為這是一種不好的實踐方式,所以你應(yīng)該使用一個安裝ID,這更容易獲取也更可靠。這樣的話就意味著,每一次用戶在每臺設(shè)備安裝一次就會產(chǎn)生一個ID。假設(shè)每個鍵值對占據(jù)32字節(jié),由于一個個人云存儲緩存最多可以有128K的大小,那么你最多可以存儲4096個字段。

在現(xiàn)實場景中,你的數(shù)據(jù)可能更加復(fù)雜。在這種情況下,存儲的數(shù)據(jù)字段數(shù)也會進一步受到限制。具體而言則需要取決于實現(xiàn),比如可能需要添加時間戳來指明每個字段是何時修改的。當你檢測到有一個字段在過去幾個禮拜或者幾個月的時間內(nèi)都沒有被修改,那么就可以安全地將它轉(zhuǎn)移到另一個字段中并刪除老的字段。

【Android Developers Training】 91. 解決云儲存沖突


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

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

【本文對您有幫助就好】

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

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 日日夜夜免费精品视频 | jiz中国| 欧美精品国产一区二区三区 | 日本一本在线观看 | 久久久噜久噜久久综合 | 久久久久久久久影院 | 91久久福利国产成人精品 | 国产不卡精品一区二区三区 | 国产国语高清在线视频二区 | 国产日韩欧美亚洲精品95 | 四虎国产精品免费久久影院 | 97在线看片免费福利视频 | 亚洲国产精品高清在线一区 | 狠狠亚洲丁香综合久久 | 一级毛片一级毛片免费毛片 | 国产深夜福利 | 精品国产一二三区在线影院 | 欧美在线观看一区 | 日本欧美一区二区三区不卡视频 | 99精品在线免费观看 | 四虎国产永久在线观看 | 国产成人亚洲综合欧美一部 | 国产亚洲精品一区二区久久 | 99久久免费精品高清特色大片 | 精品一区二区三区在线观看视频 | 色情毛片 | 日韩在线第二页 | 欧美操穴 | 久久精品伊人 | 国产日韩久久久精品影院首页 | 国产午夜免费视频 | 亚洲欧美视频二区 | 国产精品品福利视频 | 99视频精品全部国产盗摄视频 | a网在线| 免费精品精品国产欧美在线 | 99热这里都是国产精品 | 欧美日韩在线成人 | 日本不卡高清免费v日本 | 久久色精品 | 午夜dy888理论不卡达达兔 |