Statying Alive - Online and OFfline

Post on 22-Jan-2018

1.217 views 0 download

Transcript of Statying Alive - Online and OFfline

Staying aliveOnline and offline

Erik Hellman, BonTouch@ErikHellman

How well does your app work offline?

When leaving my apartment

Why?4 Reduce glitches

4 Roaming users

4 Missing coverage

4 Improve performance

4 Reduce data costs

Offline examples

How?4 Connectivity detection

4 Request queing

4 Caching

4 Preloading

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

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!

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!

NetworkInfo.State

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

NetworkInfo.DetailedState

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

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

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

15 minutes

socket timeout

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/

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

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

Request Serialzation

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

Alternatives4 Firebase

4 Couchebase

Request serialization4 Query params?

4 Request body?

4 HTTP headers?

4 Timestamp?

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

Caching4 Not HTTP Response cache!

4 Custom cache implementations

4 Don't evict when offline?

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

Caching examples

DiskLruCache. java

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/

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

4 APK Expansion files (2 * 2GB)

4 Download at first startup (unlimited)

How much data?Street addresses

4 Sweden: 650 000 ~ 7 MB

4 US: 154 million ~ 1.6 GB

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

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

Mesh networking?4 Bluetooth

4 WiFi Direct

ConclusionsDon't ignore offline!

Thanks for listening!@ErikHellman