Android Fundamentals #5- Networking

Android Fundamentals #5- Networking

3142db3adb711e247e371153b5777e04?s=128

Britt Barak

November 28, 2017
Tweet

Transcript

  1. 3as Networking Fundamentals #5 28/11/2017 Britt Barak

  2. First,

  3. Largest Android Community Android Academy - TLV TLV - Android

    Academy ~ 2000 members Join Us:
  4. Britt Barak @brittBarak • Google developer expert • Android Academy

    • Women Techmakers
  5. Android Academy Staff Yonatan Levin Google Developer Expert & CTO

    @ KolGene Britt Barak Google Developer Expert Yossi Segev Mobile engineer Colu
  6. Mentors program

  7. None
  8. None
  9. None
  10. How to perform a network request?

  11. How to perform a network request? 1. Ask permission

  12. Pleeeeeeaaaase…..?

  13. Apps must explicitly request access to resources and data outside

    their sandbox.
  14. AndroidManifest.xml <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.WRITE_CONTACTS" />

    <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  15. Normal Granted by OS Permission Types Click for documentation Dangerous

    Granted by user Click for documentation
  16. API 22- : Upon Install

  17. developer.android.com/training/permissions/requesting.html API 23+ : Runtime

  18. developer.android.com/training/permissions/requesting.html API 23+ : Runtime

  19. Questions?

  20. None
  21. Client Server Request Response

  22. • Hypertext Transfer Protocol. • Stateless protocol. • By default:

    HTTP uses port 80 and HTTPS uses port 443 HTTP
  23. Request Verb + URL (+ Payload)

  24. HTTP Verb • GET: fetch an existing resource, by the

    URL’s info. • POST: create a new resource, by the request’s payload. • PUT: update an existing resource, by the request’s payload. • DELETE: delete an existing resource.
  25. URL (Universal Resource Locator) http://www.domain.com:1234/ path/to/resource ?language=english&place=tlv protocol host port

    path Query parameters
  26. Response Status Code + Payload (body)

  27. Status Code 1xx: Informational Messages - Expect: 100-continue 2xx: Successful

    - 200 OK, 204 No Content 3xx: Redirection - Additional action needed. Commonly go to another url. 4xx: Client Error - 404 Not Found, 400 Bad Request,401 Unauthorized, 5xx: Server Error - 503 Service Unavailable
  28. Overlook

  29. URL url = new URL(myurl); HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

    urlConnection.setReadTimeout(10000 /* milliseconds */); urlConnection.setConnectTimeout(15000 /* milliseconds */); urlConnection.setRequestMethod("GET"); urlConnection.setDoInput(true); // Starts the query urlConnection.connect(); int response = urlConnection.getResponseCode(); is = urlConnection.getInputStream(); // Convert the InputStream into a string String contentAsString = readIt(is, len); return contentAsString;
  30. UI Thread #1 Rule Never block it

  31. NetworkOnMainThreadException

  32. OMG!

  33. Luckily, we have

  34. Luckily, we have square.github.io

  35. Retrofit http://square.github.io/retrofit/ https://futurestud.io/blog/retrofit-getting-started-and-android-client

  36. build.gradle() dependencies { //... implementation 'com.squareup.retrofit2:retrofit:2.3.0' }

  37. Server Json Android App Java Retrofit

  38. Request Verb + URL (+ Payload)

  39. None
  40. None
  41. https://api.foursquare.com/v2/ venues/explore Base url / Host Path / Endpoint ll

    Query
  42. static final String BASE_URL = "https://api.foursquare.com/v2/"; ServiceGenerator.java

  43. @GET("venues/explore") Call<VenuesResponse> getVenues(); public interface FoursquareService ?

  44. @GET("venues/explore") Call<VenuesResponse> getVenues(@Query("ll") String location); public interface FoursquareService

  45. @GET("venues/explore") Call<VenuesResponse> getVenues( @QueryMap Map<String, String> options); @GET("venues/{VENUE_ID}/photos") Call<PhotosResponse> getPhotos(

    @Path("VENUE_ID") String venueId); //an example I made up :) @POST("venues/add") Call<AddVenueResponse> addVenue( @Header("Authorization") String authorization, @Body("name") Venue venue);
  46. Questions?

  47. Response Status Code + Payload (body)

  48. What language does the server speak?

  49. "groups": [ { "type": "Recommended Places", "name": "recommended", "items": [

    { "reasons": { "count": 0, "items": [ { "summary": "This spot is popular", "type": "general", "reasonName": "globalInteractionReason" } ] }, "venue": {
  50. • Advanced REST Client • Postman • Swagger • ….

  51. Server Json Android App Java Serialization De-Serialization

  52. Server Json Android App Java Gson github.com/google/gson

  53. Creating the data model (POJO)

  54. "venue": { "id":"56d92e05498e6c54b6325b19", "name": "Zepra", "contact": { "phone": "036240044", "formattedPhone":"03-624-0044"

    "rating": 9.5, "hours": {...} , "photoUrl": "........" }
  55. class Venue { } "venue": { "id":"56d92e05498e6c54b6325b19", "name": "Zepra", "contact":

    { "phone": "036240044", "formattedPhone":"03-624-0044" } "rating": 9.5, "hours": {...} , "photoUrl": "........" }
  56. class Venue { String id; } "venue": { "id":"56d92e05498e6c54b6325b19", "name":

    "Zepra", "contact": { "phone": "036240044", "formattedPhone":"03-624-0044" } "rating": 9.5, "hours": {...} , "photoUrl": "........" }
  57. class Venue { String id; String name; } "venue": {

    "id":"56d92e05498e6c54b6325b19", "name": "Zepra", "contact": { "phone": "036240044", "formattedPhone":"03-624-0044" } "rating": 9.5, "hours": {...} , "photoUrl": "........" }
  58. class Venue { String id; String name; ContactInfo contact; }

    class ContactInfo { String phone; String formattedPhone; } "venue": { "id":"56d92e05498e6c54b6325b19", "name": "Zepra", "contact": { "phone": "036240044", "formattedPhone":"03-624-0044" } "rating": 9.5, "hours": {...} , "photoUrl": "........" }
  59. class Venue { String id; String name; @SerializedName("contact") ContactInfo contactInfo;

    } class ContactInfo { String phone; String formattedPhone; } "venue": { "id":"56d92e05498e6c54b6325b19", "name": "Zepra", "contact": { "phone": "036240044", "formattedPhone":"03-624-0044" } "rating": 9.5, "hours": {...} , "photoUrl": "........" }
  60. class Venue { String id; String name; @SerializedName("contact") ContactInfo contactInfo;

    } class ContactInfo { String phone; String formattedPhone; } "venue": { "id":"56d92e05498e6c54b6325b19", "name": "Zepra", "contact": { "phone": "036240044", "formattedPhone":"03-624-0044" } "rating": 9.5, "hours": {...} , "photoUrl": "........" }
  61. class Venue { String id; String name; @SerializedName("contact") ContactInfo contactInfo;

    float rating; } class ContactInfo { String phone; String formattedPhone; } "venue": { "id":"56d92e05498e6c54b6325b19", "name": "Zepra", "contact": { "phone": "036240044", "formattedPhone":"03-624-0044" } "rating": 9.5, "hours": {...} , "photoUrl": "........" }
  62. class Venue { String id; String name; @SerializedName("contact") ContactInfo contactInfo;

    float rating; } class ContactInfo { String phone; String formattedPhone; } "venue": { "id":"56d92e05498e6c54b6325b19", "name": "Zepra", "contact": { "phone": "036240044", "formattedPhone":"03-624-0044" } "rating": 9.5, "hours": {...} , "photoUrl": "........" }
  63. class Venue { String id; String name; @SerializedName("contact") ContactInfo contactInfo;

    String photoUrl; } class ContactInfo { String phone; String formattedPhone; } "venue": { "id":"56d92e05498e6c54b6325b19", "name": "Zepra", "contact": { "phone": "036240044", "formattedPhone":"03-624-0044" } "rating": 9.5, "hours": {...} , "photoUrl": "........" }
  64. Questions?

  65. {"items":[{"reasons":{"count":0,"items":[{"summary":"This spot is popular","type":"general","reasonName":"globalInteractionReason"}]},"venue":{"id ":"4b488bfff964a520184f26e3","name":"Anita La Mamma Del Gelato (הטינא)","contact":{"phone":"+97235170505","formattedPhone":"+972

    3-517-0505"},"location":{"address":"42 Shabazi St","crossStreet":"at Pines St","lat":32.06274494279335,"lng":34.76648985707776,"labeledLatLngs":[{"label":" display","lat":32.06274494279335,"lng":34.76648985707776}],"postalCode":"65150", "cc":"IL","city":"ופי-ביבא לת","state":"ביבא לת","country":" לארשי","formattedAddress":["42 Shabazi St (at Pines St)","","65150 ופי-ביבא לת לארשי"]},"categories":[{"id":"4bf58dd8d48988d1c9941735","name":"Ice Cream Shop","pluralName":"Ice Cream Shops","shortName":"Ice Cream","icon":{"prefix":"https://ss3.4sqi.net/img/categories_v2/food/icecream_", "suffix":".png"},"primary":true}],"verified":false,"stats":{"checkinsCount":1941 ,"usersCount":1192,"tipCount":78},"url":"http://www.anitaglida.co.il","price":{" tier":1,"message":"Cheap","currency":"$"},"rating":9.5,"ratingColor":"00B551","r atingSignals":310,"allowMenuUrlEdit":true,"beenHere":{"count":0,"marked":false," lastCheckinExpiredAt":0},"hours":{"status":"Open until 12:30 AM","richStatus":{"entities":[],"text":"Open until 12:30
  66. None
  67. class VenuesResponse { List<Group> groups; class Group { List<Item> items;

    } class Item { Venue venue; } }
  68. Gson gson = new Gson(); venuePojo = gson.fromJson(venueJson, Venue.class); venueJson

    = gson.toJson(venuePojo);
  69. Server Json Android App Java Retrofit GSON Converter

  70. Convertors • Gson: com.squareup.retrofit2:converter-gson • Jackson: com.squareup.retrofit2:converter-jackson • Moshi: com.squareup.retrofit2:converter-moshi

    • Protobuf: com.squareup.retrofit2:converter-protobuf • Wire: com.squareup.retrofit2:converter-wire • Simple XML: com.squareup.retrofit2:converter-simplexml • Scalars: com.squareup.retrofit2:converter-scalars
  71. Make the request already!!

  72. How to perform a network request? 1. Ask permission

  73. How to perform a network request? 1. Ask permission 2.

    Setup the Service Generator
  74. static final String BASE_URL = "https://api.foursquare.com/v2/"; ServiceGenerator.java

  75. static final String BASE_URL = "https://api.foursquare.com/v2/"; static Retrofit.Builder retrofitBuilder =

    new Retrofit.Builder() ServiceGenerator.java
  76. static final String BASE_URL = "https://api.foursquare.com/v2/"; static Retrofit.Builder retrofitBuilder =

    new Retrofit.Builder() .baseUrl(BASE_URL) ServiceGenerator.java
  77. static final String BASE_URL = "https://api.foursquare.com/v2/"; static Retrofit.Builder retrofitBuilder =

    new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()); ServiceGenerator.java
  78. Http Client OKHttp square.github.io/okhttp

  79. static OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); ServiceGenerator.java

  80. static OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); static Retrofit retrofit =

    retrofitBuilder .client(httpClient.build()) .build(); ServiceGenerator.java
  81. Question: why are ServiceGenerator fields are static?

  82. How to perform a network request? 1. Ask permission 2.

    Setup the Service Generator 3. Create the response data model
  83. class VenuesResponse { List<Group> groups; class Group { List<Item> items;

    } class Item { Venue venue; } } Rem inder
  84. How to perform a network request? 1. Ask permission 2.

    Setup the Service Generator 3. Create the response data model 4. Create the service interface
  85. @GET("venues/explore") Call<VenuesResponse> getVenues(@Query("ll") String location); public interface FoursquareService Rem inder

  86. How to perform a network request? 1. Ask permission 2.

    Setup the Service Generator 3. Create the response data model 4. Create the service interface 5. Perform Call!
  87. FoursquareService foursquareService = ServiceGenerator.retrofit .create(FoursquareService.class);

  88. FoursquareService foursquareService = ServiceGenerator.createService(FoursquareService.class); Call<VenuesResponse> call = foursquareService.getVenues(location);

  89. call.enqueue(callback); Asynchronous

  90. callback = new Callback<VenuesResponse>() { };

  91. callback = new Callback<VenuesResponse>() { @Override public void onResponse(Call<VenuesResponse> call,

    Response<VenuesResponse> response) { VenuesResponse data = response.body(); adapter.setItems(data); } };
  92. callback = new Callback<VenuesResponse>() { @Override public void onResponse(Call<VenuesResponse> call,

    Response<VenuesResponse> response) { VenuesResponse data = response.body(); //handle response data } @Override public void onFailure(...) { //handle failure } };
  93. VenuesResponse venuesResponse = call.execute().body(); Synchronous

  94. VenuesAdapter.java - (Example) public void onBindViewHolder(VenueViewHolder holder, int position) {

    textView.setText( venues.get(position).getName()); }
  95. None
  96. Questions?

  97. Load images!

  98. Challenges 1. Heavy 2. Out of memory (Exception) 3. Caching

    4. Resize 5. Image manipulation (round corners…)
  99. Picasso http://square.github.io/picasso/

  100. Server Json Android App Java Picasso OkHttp

  101. build.gradle() dependencies { //... implementation 'com.squareup.picasso:picasso:2.5.2' }

  102. Picasso .with(context) .load(url) .into(view);

  103. VenuesAdapter.java - (Example) public void onBindViewHolder(VenueViewHolder holder, int position){ textView.setText(venues.get(position).getName());

    }
  104. VenuesAdapter.java - (Example) public void onBindViewHolder(VenueViewHolder holder, int position){ textView.setText(venues.get(position).getName());

    if (! TextUtils.isEmpty(venue.getImageUrl())) { } }
  105. VenuesAdapter.java - (Example) public void onBindViewHolder(VenueViewHolder holder, int position){ textView.setText(venues.get(position).getName());

    if (! TextUtils.isEmpty(venue.getImageUrl())) { Picasso.with(imageView.getContext()) .load(venue.getImageUrl()) .into(imageView); } }
  106. None
  107. We did it!!!

  108. Network Profiler

  109. None
  110. Network Traffic Tool https://developer.android.com/studio/profile/ddms.html

  111. Facebook Stetho https://code.facebook.com/posts/393927910787513/stetho-a-new-debugging-platform-for-android/

  112. None
  113. Interceptors [Bonus]

  114. None
  115. static HttpLoggingInterceptor logging = new HttpLoggingInterceptor() .setLevel(HttpLoggingInterceptor.Level.BODY); httpClient.addInterceptor(logging) .addNetworkInterceptor(logging) //...

    ServiceGenerator.java
  116. Interceptor apiKeyInterceptor = new Interceptor() { @Override public Response intercept(Chain

    chain) throws IOException { } ServiceGenerator.java
  117. Interceptor apiKeyInterceptor = new Interceptor() { @Override public Response intercept(Chain

    chain) throws IOException { Request original = chain.request(); HttpUrl originalHttpUrl = original.url(); } ServiceGenerator.java
  118. Interceptor apiKeyInterceptor = new Interceptor() { @Override public Response intercept(Chain

    chain) throws IOException { Request original = chain.request(); HttpUrl originalHttpUrl = original.url(); HttpUrl url = originalHttpUrl.newBuilder() .addQueryParameter("client_id",CLIENT_ID) .addQueryParameter("client_secret",CLIENT_SECRET) .build(); ServiceGenerator.java
  119. ... Request.Builder requestBuilder = original.newBuilder().url(url); return chain.proceed(requestBuilder.build()); } ServiceGenerator.java

  120. httpClient.addInterceptor(logging) .addInterceptor(apiKeyInterceptor) //... ServiceGenerator.java

  121. Questions?

  122. Source code for the demo [read the ReadMe first :)

    ] https://goo.gl/WfnSpd
  123. Thank you

  124. Exercise goo.gl/BGPzkt