Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Build an efficient REST Client on Android - Droidcon IT 2016 - Matteo Gazzurelli

2,929 views

Published on

It is important to limit and optimise network traffic in mobile communications.
A well designed rest client is the best you can do in order to save network bandwidth and increase your online app responsiveness.
This talk is focused on how to create an optimal rest client with persistent cache in Android using HTTP/2, Retrofit, OkHttp and Realm while relying on an AppEngine hosted backend.

Link: http://it.droidcon.com/2016/sessions/build-an-efficient-rest-client-on-android/

Published in: Mobile
  • Be the first to comment

Build an efficient REST Client on Android - Droidcon IT 2016 - Matteo Gazzurelli

  1. 1. Build an efficient REST Client on Android
  2. 2. © DuckMa 2016 - www.duckma.com 2 Have you ever parsed a JSON string by hand? Do you still use plain HttpUrlConnection to connect to a server? Do you have an app that consumes a REST endpoint?
  3. 3. © DuckMa 2016 - www.duckma.com A Good
 REST Client THE MAIN INGREDIENTS OF A FAST WEB API 3 CachingHttp 2
  4. 4. © DuckMa 2016 - www.duckma.com HTTP 2 4 • Based on Google’s SPDY • Supported by most browsers • goals: reducing web page load latency and improving web security https://http2.github.io/faq
  5. 5. © DuckMa 2016 - www.duckma.com CACHING 5 • Caching System (Good for Dynamic APIs) • APC • Varnish • Memcache
  6. 6. © DuckMa 2016 - www.duckma.com CACHING 6 • HTTP Headers (Good for Static APIs) • Expires • Cache-Control • Entity Tags • Last-Modified
  7. 7. © DuckMa 2016 - www.duckma.com WHAT IS REST? 7 • Representational State Transfer (REST) • REST is an architectural style consisting of a coordinated set of architectural constraints applied to components, connectors, and data elements • REST is platform and language independent.
  8. 8. © DuckMa 2016 - www.duckma.com REST KEY PRINCIPLE 8 • Give every “thing” an ID • Link things together • Use standard methods • Resources with multiple representations • Communicate statelessly http://www.infoq.com/articles/rest-introduction
  9. 9. © DuckMa 2016 - www.duckma.com REST (HTTP) CLIENTS IN ANDROID 9 • DefaultHttpClient / HttpUrlConnection • Volley • Spring • Retrofit • …
  10. 10. © DuckMa 2016 - www.duckma.com WHAT IS RETROFIT 10 Type-safe HTTP client for Android and Java by Square, Inc. Uses annotations to describe HTTP requests and URL parameter replacement Retrofit turns your REST API into a Java interface.
  11. 11. © DuckMa 2016 - www.duckma.com RETROFIT CONVERTERS 11 Converters can be added to support other types. • Gson • Jackson • Moshi • Protobuffer • Wire • Simple XML • Scalars (primitives, boxed, and String)
  12. 12. © DuckMa 2016 - www.duckma.com RETROFIT 101 12 •Create a POJO/JavaBean Model •Create Retrofit Interface •Create the Call object •Execute the request •Use the result
  13. 13. © DuckMa 2016 - www.duckma.com RETROFIT MODEL EXAMPLE 13 public class Content { String id; String title; String image; public String getId() { return id; } public void setId(String id) { this.id = id; }
  14. 14. © DuckMa 2016 - www.duckma.com RETROFIT INTERFACE EXAMPLE 14 public interface AppAPI { @GET("/") @Headers({"Cache-Control: public, only-if-cached, max- stale=2147483647"}) Call<ContentResponse> loadCachedContents(); }
  15. 15. © DuckMa 2016 - www.duckma.com RETROFIT CALL EXAMPLE 15 mAppApi = retrofit.create(AppAPI.class); Call<ContentResponse> call = mAppApi.loadContents(); call.enqueue(this); @Override public void onResponse(Call<ContentResponse> call, Response<ContentResponse> response) {} @Override public void onFailure(Call<ContentResponse> call, Throwable t) {}
  16. 16. © DuckMa 2016 - www.duckma.com RETROFIT (A)SYNC CALLS 16 If you want to execute a synchronous call just replace call.enqueue() with call.execute() remember that you have to perform this outside the main thread To cancel a running request call.cancel(); calls can only be used once but you can easily clone them Call<ContentResponse> c = call.clone(); c.enqueue(this);
  17. 17. © DuckMa 2016 - www.duckma.com WHAT’S NEW IN RETROFIT 2 17 • Package with New Version (avoid conflicts) • New Service Declaration • A way to cancel the ongoing transaction • New Url resolving concept • OkHttp is now required
  18. 18. © DuckMa 2016 - www.duckma.com WHAT IS OKHTTP 18 OkHttp is an HTTP client that’s efficient by default: • HTTP/2 support allows all requests to the same host to share a socket. • Connection pooling reduces request latency (if HTTP/2 isn’t available). • Transparent GZIP shrinks download sizes. • Response caching avoids the network completely for repeat requests
  19. 19. © DuckMa 2016 - www.duckma.com OKHTTP - NOT ONLY FOR RETROFIT 19 Can be used as http client for other libraries: • Picasso • Glide • Fresco Okio Dependent: Okio is a new library that complements java.io and java.nio to make it much easier to access, store, and process your data.
  20. 20. © DuckMa 2016 - www.duckma.com INTERCEPTORS 20 Powerful mechanism that can monitor, rewrite, and retry calls. Interceptors can be chained and are called in order. https://github.com/square/okhttp/wiki/Interceptors
  21. 21. © DuckMa 2016 - www.duckma.com RETROFIT AND OKHTTP INTERCEPTOR 21 OkHttpClient client = new OkHttpClient(); client.interceptors().add(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Response response = chain.proceed(chain.request()); return response; } }); Retrofit retrofit = new Retrofit.Builder() .baseUrl(“http://test-project-json.appspot.com”) .addConverterFactory(GsonConverterFactory.create()) .client(client) .build();
  22. 22. © DuckMa 2016 - www.duckma.com LOGGING 22 Latest version of OkHttp ships with a logging interceptor compile 'com.squareup.okhttp3:logging-interceptor:3.2.0' HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(interceptor).build();
  23. 23. © DuckMa 2016 - www.duckma.com TWO LEVEL OF CACHING 23 • Soft Caching (Network level) • Persistent Caching (Database)
  24. 24. © DuckMa 2016 - www.duckma.com SOFT CACHING WITH OKHTTP 24 •OkHttp as caching bucket •Response caching uses HTTP headers for all configuration. •There are cache headers to force a cached response, force a network response, or force the network response to be validated with a conditional GET.
  25. 25. © DuckMa 2016 - www.duckma.com SOFT CACHING WITH OKHTTP 25 OkHttpClient.Builder okBuilder = new OkHttpClient.Builder(); Cache cache = new Cache(new File(getCacheDir(), CACHE_DIR), CACHE_SIZE); okBuilder.cache(cache); Private cache directory
  26. 26. © DuckMa 2016 - www.duckma.com PERSISTENT CACHING 26 Various Android Storage Options: •Shared Preferences •Internal/External Storage •Sqlite •Realm.io
  27. 27. © DuckMa 2016 - www.duckma.com REALM.IO 27 Realm is a replacement for SQLite • Uses little resources • Easy to use • Fast • Cross-Platform (C++) • Advanced https://realm.io/docs/java/latest/#getting-started
  28. 28. © DuckMa 2016 - www.duckma.com REALM IS FAST 28 Tests run on an Galaxy S3, using the latest available version of each library as of Sept 28, 2014.
  29. 29. © DuckMa 2016 - www.duckma.com REALM LIST / PROXY CLASSES 29 The RealmProxy classes are our way of making sure that the Realm object doesn’t contain any data itself, but instead access the data directly in the database.
  30. 30. © DuckMa 2016 - www.duckma.com REALM WITH RETROFIT 30 https://realm.io/docs/java/latest/#retrofit Retrofit does not automatically add objects to Realm, instead you must manually add them using the realm.copyToRealm() or realm.copyToRealmOrUpdate() methods.
  31. 31. © DuckMa 2016 - www.duckma.com REALM WITH RETROFIT 31 @Override public void onResponse(Call<ContentResponse> call, Response<ContentResponse> response) { if (response.isSuccessful()) { mRealm.beginTransaction(); mRealm.copyToRealm(mContentsArray); mRealm.commitTransaction(); } }
  32. 32. © DuckMa 2016 - www.duckma.com BACKEND? APPENGINE 32 Easy and fast way to create http2 backend https://console.developers.google.com.
  33. 33. © DuckMa 2016 - www.duckma.com APPENGINE - FLASK (PYTHON) 33 @app.route('/') def returnJson(): folder = 'json/app.json' f = open(folder,'r') resp = Response(response=f.read(), status=200, mimetype="application/json") return resp Create a static json file to be served
  34. 34. © DuckMa 2016 - www.duckma.com BACKEND? 34 http://blog.duckma.com/2016/01/how-to-create- simple-project-in-google.html If you want to start using Google App Engine, Start Here: https://console.cloud.google.com/start/appengine
  35. 35. © DuckMa 2016 - www.duckma.com DEMO 35 https://github.com/duckma/Rest-Client-Demo • Retrofit • Gson • Interceptor • OkHTTP • Caching • realm.io
  36. 36. © DuckMa 2016 - www.duckma.com DEMO 36 Download app: duk.ma/droidconit2016
  37. 37. © DuckMa 2016 - www.duckma.com DEMO SOFT CACHE 37 • D/OkHttp: --> GET http://test-project-json.appspot.com/ • D/OkHttp: --> END GET • D/OkHttp: <-- 200 OK http://test-project-json.appspot.com/ (322ms) • D/OkHttp: <-- END HTTP • D/OkHttp: --> GET http://test-project-json.appspot.com/ • D/OkHttp: Cache-Control: public, only-if-cached, max-stale=2147483647 • D/OkHttp: --> END GET • D/OkHttp: <-- 200 OK http://test-project-json.appspot.com/ (6ms) • D/OkHttp: Warning: 110 HttpURLConnection "Response is stale" • D/OkHttp: <-- END HTTP
  38. 38. © DuckMa 2016 - www.duckma.com RETROFIT INTERFACE EXAMPLE 38 public interface AppAPI { String FORCE_CACHE_HEADERS = "Cache-Control: public, only-if-cached, max-stale=" + Integer.MAX_VALUE; @GET("/") Call<ContentResponse> loadContents(); @GET("/") @Headers({FORCE_CACHE_HEADERS}) Call<ContentResponse> loadCachedContents(); }
  39. 39. © DuckMa 2016 - www.duckma.com DEMO PERSISTENT CACHE 39 @Override public void onFailure(Call<ContentResponse> call, Throwable t) { RealmResults<Content> results = mRealm.where(Content.class).findAll(); mContentsArray.addAll(results); mAdapter.notifyDataSetChanged();
  40. 40. © DuckMa 2016 - www.duckma.com SAVE DATA IN REALM 40 @Override public void onResponse(Call<ContentResponse> call, Response<ContentResponse> response) { mContentsArray.clear(); if (response.isSuccessful()) { mContentsArray.addAll(response.body().getContents()); mRealm.beginTransaction(); mRealm.copyToRealm(mContentsArray); mRealm.commitTransaction();
  41. 41. © DuckMa 2016 - www.duckma.com CONTENT MODEL 41 public class Content extends RealmObject { String id; String title; String image; public String getId() { return id; } public void setId(String id) { this.id = id; }
  42. 42. © DuckMa 2016 - www.duckma.com GSON CONVERTER 42 Gson gson = new GsonBuilder() .setExclusionStrategies(new ExclusionStrategy() { @Override public boolean shouldSkipField(FieldAttributes f) { return f.getDeclaringClass().equals(RealmObject.class); } @Override public boolean shouldSkipClass(Class<?> clazz) { return false; } }) .create(); https://code.google.com/p/google-gson/issues/detail?id=440
  43. 43. © DuckMa 2016 - www.duckma.com RETROFIT CLIENT WITH OKHTTP 43 OkHttpClient.Builder okBuilder = new OkHttpClient.Builder(); Cache cache = new Cache(new File(getCacheDir(), CACHE_DIR), CACHE_SIZE); okBuilder.cache(cache); HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor(); logInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS); okBuilder.addInterceptor(logInterceptor); Retrofit retrofit = new Retrofit.Builder() .baseUrl(Config.ENDPOINT) .addConverterFactory(GsonConverterFactory.create(gson)) .client(okBuilder.build()) .build();
  44. 44. © DuckMa 2016 - www.duckma.com WHO AM I ? 44 Matteo Gazzurelli CEO DuckMa DuckMa is a mobile focused design and software boutique primarily working with startups and leading brands. We are a group of passionate professionals who make handcrafted mobile native apps. San FranciscoBrescia
  45. 45. © DuckMa 2016 - www.duckma.com THANK YOU 45 We are hiring! duk.ma/jobpositions

×