+ All Categories
Home > Mobile > Statying Alive - Online and OFfline

Statying Alive - Online and OFfline

Date post: 22-Jan-2018
Category:
Upload: erik-hellman
View: 1,217 times
Download: 0 times
Share this document with a friend
48
Staying alive Online and offline Erik Hellman, BonT ouch @ErikHellman
Transcript
Page 1: Statying Alive - Online and OFfline

Staying aliveOnline and offline

Erik Hellman, BonTouch@ErikHellman

Page 2: Statying Alive - Online and OFfline

How well does your app work offline?

Page 3: Statying Alive - Online and OFfline

When leaving my apartment

Page 4: Statying Alive - Online and OFfline
Page 5: Statying Alive - Online and OFfline
Page 6: Statying Alive - Online and OFfline

Why?4 Reduce glitches

4 Roaming users

4 Missing coverage

4 Improve performance

4 Reduce data costs

Page 7: Statying Alive - Online and OFfline

Offline examples

Page 8: Statying Alive - Online and OFfline
Page 9: Statying Alive - Online and OFfline
Page 10: Statying Alive - Online and OFfline
Page 11: Statying Alive - Online and OFfline
Page 12: Statying Alive - Online and OFfline

How?4 Connectivity detection

4 Request queing

4 Caching

4 Preloading

Page 13: Statying Alive - Online and OFfline

Challenges4 Captive Portals

4 Network handover

4 Temporary network loss

4 Timeouts

4 2G Voice and Data

4 Local Storage

4 Request Serialization

4 ...and more

Page 14: Statying Alive - Online and OFfline

Detecting connectivityboolean isNetworkAvailable() { ConnectivityManager mgr = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE); NetworkInfo networkInfo = mgr.getActiveNetworkInfo(); return networkInfo != null && networkInfo.isConnected();}

4 Checks network state right now

4 Captive portals detection (since API level 17)

4 Poor networks (since API level 16)

4 Must be called before every network operation

4 Will indicate DISCONNECTED if background data is disabled!

Page 15: Statying Alive - Online and OFfline

Listen for changesprivate void setupNetworkChangeListener() { IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); this.networkStateReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { ConnectivityManager mgr = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE); NetworkInfo networkInfo = mgr.getActiveNetworkInfo(); notifyNetworkState(networkInfo != null && networkInfo.isConnected()); } }; registerReceiver(networkStateReceiver, intentFilter);}

4 Continously listen for network state changes

4 Remember to unregister!

Page 16: Statying Alive - Online and OFfline

NetworkInfo.State

public enum State { CONNECTING, CONNECTED, SUSPENDED, DISCONNECTING, DISCONNECTED, UNKNOWN}

Page 17: Statying Alive - Online and OFfline

NetworkInfo.DetailedState

public enum DetailedState { IDLE, SCANNING, CONNECTING, AUTHENTICATING, OBTAINING_IPADDR, CONNECTED, SUSPENDED, DISCONNECTING, DISCONNECTED, FAILED, BLOCKED, VERIFYING_POOR_LINK, CAPTIVE_PORTAL_CHECK}

Page 18: Statying Alive - Online and OFfline

private static final EnumMap<DetailedState, State> stateMap = new EnumMap<DetailedState, State>(DetailedState.class);

static { stateMap.put(DetailedState.IDLE, State.DISCONNECTED); stateMap.put(DetailedState.SCANNING, State.DISCONNECTED); stateMap.put(DetailedState.CONNECTING, State.CONNECTING); stateMap.put(DetailedState.AUTHENTICATING, State.CONNECTING); stateMap.put(DetailedState.OBTAINING_IPADDR, State.CONNECTING); stateMap.put(DetailedState.VERIFYING_POOR_LINK, State.CONNECTING); stateMap.put(DetailedState.CAPTIVE_PORTAL_CHECK, State.CONNECTING); stateMap.put(DetailedState.CONNECTED, State.CONNECTED); stateMap.put(DetailedState.SUSPENDED, State.SUSPENDED); stateMap.put(DetailedState.DISCONNECTING, State.DISCONNECTING); stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED); stateMap.put(DetailedState.FAILED, State.DISCONNECTED); stateMap.put(DetailedState.BLOCKED, State.DISCONNECTED);}

Page 19: Statying Alive - Online and OFfline

Unexpected conditions4 2G Voice and Data

4 Flight Mode

public static boolean isAirplaneModeOn(Context context) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { return Settings.System.getInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) != 0; } else { return Settings.Global.getInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) != 0; } }

Page 20: Statying Alive - Online and OFfline
Page 21: Statying Alive - Online and OFfline
Page 22: Statying Alive - Online and OFfline
Page 23: Statying Alive - Online and OFfline

15 minutes

socket timeout

Page 24: Statying Alive - Online and OFfline

Response Times:The 3 Important Limits4 0.1 seconds - system is reacting instantaneously

4 1.0 seconds - limit for user's flow of thought to stay uninterrupted

4 10 seconds - limit for keeping the user's attention

...response time guidelines for web-based applications are the same as for all other applications...

— Jakob Nielsen, http://www.nngroup.com/articles/response-times-3-important-limits/

Page 25: Statying Alive - Online and OFfline

Timeout for HttpURLConnectionURL url = new URL(url);HttpURLConnection urlConnection = url.openConnection();urlConnection.setConnectTimeout(CONNECTION_TIMEOUT);urlConnection.setReadTimeout(CONNECTION_TIMEOUT);

Page 26: Statying Alive - Online and OFfline

Timeout for OkHttpClientOkHttpClient client = new OkHttpClient();client.setConnectTimeout(CONNECTION_TIMEOUT);client.setReadTimeout(CONNECTION_TIMEOUT);

Page 27: Statying Alive - Online and OFfline

Request Serialzation

Page 28: Statying Alive - Online and OFfline
Page 29: Statying Alive - Online and OFfline
Page 30: Statying Alive - Online and OFfline

Queing outgoing requests// In your ActivitystartService(buildRequestIntent(url, data));

// IntentService.onHandleIntent()is(isConnected(this)) { performRequest(url, data);} else { serializeRequest(url, data);}

// BroadcastReceiver listening for network changesif(isConnected(context)) { context.startService(new Intent(ACTION_SEND_QUEUED_REQUESTS));}

Page 31: Statying Alive - Online and OFfline

Alternatives4 Firebase

4 Couchebase

Page 32: Statying Alive - Online and OFfline

Request serialization4 Query params?

4 Request body?

4 HTTP headers?

4 Timestamp?

Page 33: Statying Alive - Online and OFfline

Request serializationpublic void serializeRequest(url, data) { ContentValues values = new ContentValues(); values.put("url", url); values.put("data", data); getContentResolver.insert(...);}

Page 34: Statying Alive - Online and OFfline

Caching4 Not HTTP Response cache!

4 Custom cache implementations

4 Don't evict when offline?

4 Context.getCacheDir(), Context.getFilesDir() or Context.getExternalFilesDir()?

Page 35: Statying Alive - Online and OFfline

Caching examples

Page 36: Statying Alive - Online and OFfline
Page 37: Statying Alive - Online and OFfline
Page 38: Statying Alive - Online and OFfline
Page 39: Statying Alive - Online and OFfline
Page 40: Statying Alive - Online and OFfline

DiskLruCache. java

Page 41: Statying Alive - Online and OFfline

Load from cache or network?// Our sources (left as an exercise for the reader)Observable<Data> memory = ...; Observable<Data> disk = ...; Observable<Data> network = ...;

// Retrieve the first source with dataObservable<Data> source = Observable .concat(memory, disk, network) .first();

4 Dan Lew, http://blog.danlew.net/2015/06/22/loading-data-from-multiple-sources-with-rxjava/

Page 42: Statying Alive - Online and OFfline

Preload data for offline4 Assets or Raw resources (100 MB)

4 APK Expansion files (2 * 2GB)

4 Download at first startup (unlimited)

Page 43: Statying Alive - Online and OFfline

How much data?Street addresses

4 Sweden: 650 000 ~ 7 MB

4 US: 154 million ~ 1.6 GB

Page 44: Statying Alive - Online and OFfline

Preloading SQLite DBprivate SQLiteDatabase openPreloadedSQLiteDB() { File localCopy = new File(getFilesDir(), DB_NAME); if (localCopy.exists()) { // TODO Perform version check! InputStream inputStream = getResources().openRawResource(R.raw.preloaded_db); readStreamToFile(inputStream, localCopy); } return SQLiteDatabase.openOrCreateDatabase(localCopy, null);}

Page 45: Statying Alive - Online and OFfline

Local storage4 Micromax Canvas A1 (Android One) - 2GB internal

storage

4 Use external storagepublic static void saveFileToExternalStorage(Context context, String filename, byte[] data) { File appPrivateFile = new File(context.getExternalFilesDir(null), filename); writeBytesToFile(data, appPrivateFile);}

Page 46: Statying Alive - Online and OFfline

Mesh networking?4 Bluetooth

4 WiFi Direct

Page 47: Statying Alive - Online and OFfline

ConclusionsDon't ignore offline!

Page 48: Statying Alive - Online and OFfline

Thanks for listening!@ErikHellman


Recommended