sync on android

83
Sync ON ANDROID Jerzy Chalupski chalup [email protected]

Upload: chalup

Post on 23-Jun-2015

4.822 views

Category:

Technology


0 download

DESCRIPTION

Talk about standard synchronisation pattern on Android (SyncAdapter + Authenticator + ContentProvider). Presentation given at KrakDroid 2012 (http://www.krakdroid.pl). Video from the talk (in Polish): http://www.youtube.com/watch?v=8Oti4qf7P84.

TRANSCRIPT

Page 1: Sync on Android

SyncON ANDROID

Jerzy Chalupski

chalup

[email protected]

Page 2: Sync on Android

What we do in general...

Page 3: Sync on Android

What we do ALL THE TIME

sync, sync, sync, sync

Page 4: Sync on Android

SyncON ANDROID

OVERVIEW ARCHITECTURE

CONTENT PROVIDER PITFALLS & PROTIPS

Page 5: Sync on Android

SyncON ANDROID

OVERVIEW ARCHITECTURE

CONTENT PROVIDER PITFALLS & PROTIPS

Page 6: Sync on Android

Not exactly the fresh topic...

„Developing Android REST client applications”

by Virgil Dobjanschi@Google I/O 2010

Page 7: Sync on Android

Not exactly the fresh topic...

„Synchronizacja danych z serwisamiwebowymi w Androidzie”

by Bartosz Filipowicz@KrakDroid 2011

Page 8: Sync on Android

...but there is still much confusion

Not exactly the fresh topic...

„Synchronizacja danych z serwisamiwebowymi w Androidzie”

by Bartosz Filipowicz@KrakDroid 2011

Page 9: Sync on Android

ContentProvider

ContentResolver

SyncManager

SyncAdapter

Authenticator

AccountManager

UI

Page 10: Sync on Android

„Wat? Why do I need to write all this crap, sync is just fetching data from server”

typical reaction

Page 11: Sync on Android

Sync provides data sharing

Page 12: Sync on Android

Sync provides data sharing

offline mode

Page 13: Sync on Android

Sync provides data sharing

offline mode

responsive UI

Page 14: Sync on Android

Sync provides data sharing

offline mode

responsive UI

GREAT UX

Page 15: Sync on Android

SyncON ANDROID

OVERVIEW ARCHITECTURE

CONTENT PROVIDER PITFALLS & PROTIPS

Page 16: Sync on Android

ContentProvider 101: CRUD

CREATE

READ

UPDATE

DELETE

insert()

query()

update()

delete()

Page 17: Sync on Android

ContentProvider 101: URI

content://com.futuresimple.krakdroid.Provider/datasets/1

Page 18: Sync on Android

ContentProvider 101: URI

content://com.futuresimple.krakdroid.Provider/datasets/1

Page 19: Sync on Android

ContentProvider 101: URI

content://com.futuresimple.krakdroid.Provider/datasets/1

Page 20: Sync on Android

ContentProvider 101: URI

content://com.futuresimple.krakdroid.Provider/datasets/1

Page 21: Sync on Android

ContentProvider 101: notifications

content://com.futuresimple.krakdroid.Provider/datasets/1content://com.futuresimple.krakdroid.Provider/solutionscontent://com.futuresimple.krakdroid.Provider/solutions/1content://com.futuresimple.krakdroid.Provider/solutions/1/answers/1content://com.futuresimple.krakdroid.Provider/solutions/1/answers/2content://com.futuresimple.krakdroid.Provider/solutions/2/answers/1

Page 22: Sync on Android

ContentResolver.notifyChange(“content://com.futuresimple.krakdroid.Provider/datasets/1”);

content://com.futuresimple.krakdroid.Provider/datasets/1content://com.futuresimple.krakdroid.Provider/solutionscontent://com.futuresimple.krakdroid.Provider/solutions/1content://com.futuresimple.krakdroid.Provider/solutions/1/answers/1content://com.futuresimple.krakdroid.Provider/solutions/1/answers/2content://com.futuresimple.krakdroid.Provider/solutions/2/answers/1

ContentProvider 101: notifications

Page 23: Sync on Android

ContentResolver.notifyChange(“content://com.futuresimple.krakdroid.Provider/solutions/1/answers/1”);

content://com.futuresimple.krakdroid.Provider/datasets/1content://com.futuresimple.krakdroid.Provider/solutionscontent://com.futuresimple.krakdroid.Provider/solutions/1content://com.futuresimple.krakdroid.Provider/solutions/1/answers/1content://com.futuresimple.krakdroid.Provider/solutions/1/answers/2content://com.futuresimple.krakdroid.Provider/solutions/2/answers/1

ContentProvider 101: notifications

Page 24: Sync on Android

SyncON ANDROID

OVERVIEW ARCHITECTURE

CONTENT PROVIDER PITFALLS & PROTIPS

Page 25: Sync on Android

ContentProvider

ContentResolver

SyncManager

SyncAdapter

Authenticator

AccountManager

UI

Page 26: Sync on Android

AccountManager

addAccount()

ContentResolverSyncManager

SyncAdapter ContentProvider

Authenticator

UI

Sync architectureCREATING NEW ACCOUNT

Page 27: Sync on Android

AccountManager

addAccount()

addAccount()

ContentResolverSyncManager

SyncAdapter ContentProvider

Authenticator

UI

Sync architectureCREATING NEW ACCOUNT

Page 28: Sync on Android

AccountManager

addAccount()

addAccount()

ContentResolverSyncManager

SyncAdapter ContentProvider

Authenticator

UI

Sync architectureCREATING NEW ACCOUNT

Page 29: Sync on Android

AccountManager

ContentResolver

UI

ContentProvider

Sync architecture SHOW SYNCED DATA

Authenticator

query()

query()

SyncManager

SyncAdapter

Page 30: Sync on Android

AccountManager

ContentResolver

UI

SyncManager

SyncAdapter ContentProvider

Sync architecture REQUEST SYNC

Authenticator

getAccountsByType()

Page 31: Sync on Android

AccountManager

ContentResolver

UI

SyncManager

SyncAdapter ContentProvider

Sync architecture REQUEST SYNC

Authenticator

getAccountsByType()

requestSync()

Page 32: Sync on Android

AccountManager

ContentResolver

UI

SyncManager

SyncAdapter ContentProvider

Sync architecture REQUEST SYNC

Authenticator

getAccountsByType()

requestSync()

onPerformSync()

Page 33: Sync on Android

AccountManager

ContentResolver

UI

SyncManager

SyncAdapter ContentProvider

Sync architecture EDIT DATA

Authenticator

insert()

insert()

Page 34: Sync on Android

AccountManager

ContentResolver

UI

SyncManager

SyncAdapter ContentProvider

Sync architecture EDIT DATA

Authenticator

insert()

insert()notifyChange()

Page 35: Sync on Android

AccountManager

ContentResolver

UI

SyncManager

SyncAdapter ContentProvider

Sync architecture EDIT DATA

Authenticator

insert()

insert()notifyChange()

Page 36: Sync on Android

AccountManager

ContentResolver

UI

SyncManager

SyncAdapter ContentProvider

Sync architecture EDIT DATA

Authenticator

getAccountsByType()

insert()

insert()notifyChange()

Page 37: Sync on Android

AccountManager

ContentResolver

UI

SyncManager

SyncAdapter ContentProvider

Sync architecture EDIT DATA

Authenticator

getAccountsByType()

onPerformSync()

insert()

insert()notifyChange()

Page 38: Sync on Android

AccountManager

ContentResolver

UI

SyncManager

SyncAdapter ContentProvider

Sync architecture POST NEW DATA

Authenticator

onPerformSync()

Page 39: Sync on Android

AccountManager

ContentResolver

UI

SyncManager

SyncAdapter ContentProvider

Sync architecture POST NEW DATA

Authenticator

getAuthToken()

onPerformSync()

Page 40: Sync on Android

AccountManager

ContentResolver

UI

SyncManager

SyncAdapter ContentProvider

Sync architecture POST NEW DATA

Authenticator

getAuthToken()

query()query()onPerformSync()

Page 41: Sync on Android

AccountManager

ContentResolver

UI

SyncManager

SyncAdapter ContentProvider

Sync architecture POST NEW DATA

Authenticator

getAuthToken()

query()query()

POST

onPerformSync()

Page 42: Sync on Android

AccountManager

ContentResolver

UI

SyncManager

SyncAdapter ContentProvider

Sync architecture GET NEW DATA

Authenticator

onPerformSync()

Page 43: Sync on Android

AccountManager

ContentResolver

UI

SyncManager

SyncAdapter ContentProvider

Sync architecture GET NEW DATA

Authenticator

getAuthToken()

onPerformSync()

Page 44: Sync on Android

AccountManager

ContentResolver

UI

SyncManager

SyncAdapter ContentProvider

Sync architecture GET NEW DATA

Authenticator

getAuthToken()

GET

onPerformSync()

Page 45: Sync on Android

AccountManager

ContentResolver

UI

SyncManager

SyncAdapter ContentProvider

Sync architecture GET NEW DATA

Authenticator

getAuthToken()

applyBatch()

GET

applyBatch()

onPerformSync()

Page 46: Sync on Android

AccountManager

ContentResolver

UI

SyncManager

SyncAdapter ContentProvider

Sync architecture GET NEW DATA

Authenticator

getAuthToken()

applyBatch()notifyChange()

GET

applyBatch()

onPerformSync()

Page 47: Sync on Android

AccountManager

ContentResolver

UI

SyncManager

SyncAdapter ContentProvider

Sync architecture GET NEW DATA

Authenticator

getAuthToken()

applyBatch()notifyChange()

GET

applyBatch()

onPerformSync()

onLoaderFinished()

Page 48: Sync on Android

AccountManager

ContentResolver

UI

SyncManager

SyncAdapter ContentProvider

Authenticator Sync architecture WIN #1: NO REMOTE I/O IN UI

Page 49: Sync on Android

AccountManager

ContentResolver

UI

SyncManager

SyncAdapter ContentProvider

Authenticator Sync architecture WIN #2: SYNC SCHEDULING

Page 50: Sync on Android

SyncON ANDROID

OVERVIEW ARCHITECTURE

CONTENT PROVIDER PITFALLS & PROTIPS

Page 51: Sync on Android

IDs in ContentProvider URIs

content://com.futuresimple.krakdroid.Provider/datasets/1

Page 52: Sync on Android

IDs in ContentProvider URIs

content://com.futuresimple.krakdroid.Provider/datasets/1

Plan A: Use local IDs! (BaseColumns._ID)

Page 53: Sync on Android

IDs in ContentProvider URIs

content://com.futuresimple.krakdroid.Provider/datasets/1

Plan A: Use local IDs! (BaseColumns._ID)

ISSUE: still need server-side IDs for relations

Page 54: Sync on Android

IDs in ContentProvider URIs

content://com.futuresimple.krakdroid.Provider/datasets/1

Plan A: Use local IDs! (BaseColumns._ID)

ISSUE: still need server-side IDs for relationsISSUE: conversions between server and local IDs

Page 55: Sync on Android

IDs in ContentProvider URIs

content://com.futuresimple.krakdroid.Provider/datasets/15002900

Plan B: OK, use server-side IDs!

Page 56: Sync on Android

IDs in ContentProvider URIs

content://com.futuresimple.krakdroid.Provider/datasets/15002900

Plan B: OK, use server-side IDs!

ISSUE: what about offline mode?

Page 57: Sync on Android

IDs in ContentProvider URIs

content://com.futuresimple.krakdroid.Provider/datasets/-42

Plan C: OK, let’s mix things up!

content://com.futuresimple.krakdroid.Provider/datasets/15002900

Page 58: Sync on Android

IDs in ContentProvider URIs

content://com.futuresimple.krakdroid.Provider/datasets/-42

Plan C: OK, let’s mix things up!

ISSUE: very tricky implementation

content://com.futuresimple.krakdroid.Provider/datasets/15002900

Page 59: Sync on Android

IDs in ContentProvider URIs

content://com.futuresimple.krakdroid.Provider/datasets/GUID

Plan D: GUID

Page 60: Sync on Android

IDs in ContentProvider URIs

content://com.futuresimple.krakdroid.Provider/datasets/GUID

Plan D: GUID

ISSUE: needs support on the backend

Page 63: Sync on Android

Deleting an account

From your app

From system settings

From 3rd party app

Page 64: Sync on Android

Deleting an account

From your app

From system settings

From 3rd party app

“Where should I perform user

data cleanup?”

Page 65: Sync on Android

Deleting an account

@Override getAccountRemovalAllowed()

Page 66: Sync on Android

Deleting an account

@Override getAccountRemovalAllowed()

CONS: depends on current Settings implementation.

PROS: exactly the thing you need.

Page 67: Sync on Android

Deleting an account

<receiver android:name=".auth.AccountBroadcastReceiver" android:enabled="true" > <intent-filter> <action android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED" /> </intent-filter></receiver>

Page 68: Sync on Android

Deleting an account

<receiver android:name=".auth.AccountBroadcastReceiver" android:enabled="true" > <intent-filter> <action android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED" /> </intent-filter></receiver>

CONS: only info about existing accounts.

PROS: peace of mind.

Page 69: Sync on Android

Sync lifecycle

Happy case:

Page 70: Sync on Android

Sync lifecycle

Happy case:

requestSync()

Page 71: Sync on Android

onPerformSync()

Sync lifecycle

requestSync()

Happy case:

Page 72: Sync on Android

onPerformSync()

Sync lifecycle

requestSync() onStatusChanged()

Happy case:

Page 73: Sync on Android

onPerformSync()

Sync lifecycle

Not-so-happy case:

requestSync() onStatusChanged()

Page 74: Sync on Android

onPerformSync()

Sync lifecycle

Not-so-happy case:

onStatusChanged()requestSync()

Page 75: Sync on Android

onPerformSync()

Sync lifecycle

Not-so-happy case:

requestSync() cancelSync()+

onStatusChanged()

Page 76: Sync on Android

Futureproof your sync

Page 77: Sync on Android

Futureproof your sync

1. Be lenient on GET

Page 78: Sync on Android

Futureproof your sync

1. Be lenient on GET

2. Be strict on POST

Page 79: Sync on Android

Futureproof your sync

3. Have resync in v1.0

1. Be lenient on GET

2. Be strict on POST

Page 80: Sync on Android

?

Page 81: Sync on Android
Page 82: Sync on Android
Page 83: Sync on Android

Thanks.