本指南說明如何實作日曆資料的增量同步。使用這個方法,您可以在節省頻寬的同時,讓所有日曆集合的資料保持同步。
目錄
總覽
增量同步包含兩個階段:
初始完整同步:在開始時執行一次,將用戶端狀態與伺服器狀態完整同步。用戶端會取得必須保留的同步權杖。
遞增同步:重複執行,以更新用戶端自上次同步後的所有變更。每次用戶端都會提供從伺服器取得的先前同步權杖,並儲存回應中的新同步權杖。
初始完整同步
初始完整同步是針對要同步的集合中所有資源的原始要求。如果只想同步處理特定資源子集,可以視需要使用要求參數限制清單要求。
在清單作業的回應中,回應會包含名為 nextSyncToken 的欄位,代表同步符記。您必須儲存 nextSyncToken 的值。如果結果集過大且回應是分頁,則 nextSyncToken
欄位只會出現在最後一頁。
遞增同步
增量同步可讓您擷取自上次同步要求後修改的所有資源。如要這麼做,請執行清單要求,並在 syncToken 欄位中指定最近的同步權杖。請注意,結果一律會包含已刪除的項目,因此用戶端可以從儲存空間中移除這些項目。
如果自上次增量同步要求後,有大量資源發生變更,清單結果中可能會顯示 pageToken,而非 syncToken。在這些情況下,請執行與用於擷取增量同步中第一頁的相同清單查詢 (使用相同的 syncToken),將 pageToken 附加至該查詢,並透過後續要求分頁,直到在最後一頁找到另一個 syncToken 為止。儲存這個 syncToken,以供下一個同步要求使用。
以下範例顯示增量分頁同步:
原始查詢
GET /calendars/primary/events?maxResults=10&singleEvents=true&syncToken=CPDAlvWDx70CEPDAlvWDx
結果包含下列項目:
{
"nextPageToken": "CiAKGjBpNDd2Nmp2Zml2cXRwYjBpOXA"
}
正在擷取下一頁
GET /calendars/primary/events?maxResults=10&singleEvents=true&syncToken=CPDAlvWDx70CEPDAlvWDx&pageToken=CiAKGjBpNDd2Nmp2Zml2cXRwYjBpOXA
伺服器要求完整同步
有時伺服器會因權杖過期或相關存取控制清單 (ACL) 變更,而使同步權杖失效。在這種情況下,伺服器會以 HTTP 狀態碼 410 回應增量要求。發生這種情況時,請清除用戶端儲存空間,然後執行新的完整同步作業。
程式碼範例
以下範例說明如何搭配使用同步權杖和 Java 用戶端程式庫。第一次呼叫 run() 方法時,系統會執行完整同步作業並儲存同步權杖。後續每次執行時,都會載入已儲存的同步權杖,並執行增量同步。
private static void run() throws IOException { // Construct the {@link Calendar.Events.List} request, but don't execute it yet. Calendar.Events.List request = client.events().list("primary"); // Load the sync token stored from the last execution, if any. String syncToken = syncSettingsDataStore.get(SYNC_TOKEN_KEY); if (syncToken == null) { System.out.println("Performing full sync."); // Set the filters you want to use during the full sync. Sync tokens aren't compatible with // most filters, but you may want to limit your full sync to only a certain date range. // In this example we are only syncing events up to a year old. Date oneYearAgo = Utils.getRelativeDate(java.util.Calendar.YEAR, -1); request.setTimeMin(new DateTime(oneYearAgo, TimeZone.getTimeZone("UTC"))); } else { System.out.println("Performing incremental sync."); request.setSyncToken(syncToken); } // Retrieve the events, one page at a time. String pageToken = null; Events events = null; do { request.setPageToken(pageToken); try { events = request.execute(); } catch (GoogleJsonResponseException e) { if (e.getStatusCode() == 410) { // A 410 status code, "Gone", indicates that the sync token is invalid. System.out.println("Invalid sync token, clearing event store and re-syncing."); syncSettingsDataStore.delete(SYNC_TOKEN_KEY); eventDataStore.clear(); run(); } else { throw e; } } List<Event> items = events.getItems(); if (items.size() == 0) { System.out.println("No new events to sync."); } else { for (Event event : items) { syncEvent(event); } } pageToken = events.getNextPageToken(); } while (pageToken != null); // Store the sync token from the last request to be used during the next execution. syncSettingsDataStore.set(SYNC_TOKEN_KEY, events.getNextSyncToken()); System.out.println("Sync complete."); }
舊版同步
如要同步處理事件集合,請先儲存事件清單要求中的 updated 欄位值,然後使用 updatedMin 欄位擷取更新的事件。這種做法較容易出錯 (例如不會強制執行查詢限制),而且只適用於事件,因此不建議使用。