Differences

This shows you the differences between two versions of the page.

Link to this comparison view

smd:laboratoare:05 [2021/02/28 19:50]
adriana.draghici [Lab 5. HTTP and web services]
smd:laboratoare:05 [2021/05/18 22:17] (current)
adriana.draghici [Tasks]
Line 1: Line 1:
 ===== Lab 5. HTTP and web services ===== ===== Lab 5. HTTP and web services =====
-<note important>​This page hasn't been updated yet for the 2021 semester and may contain outdated information</​note>​ 
  
 ==== Objectives ==== ==== Objectives ====
Line 43: Line 42:
 </​code>​ </​code>​
  
-If order for the network request to work we need to have neccessary ​permissions:​ +If order for the network request to work we need to have necessary ​permissions:​ 
-  * For access to Internet+  * For Internet ​access
    
 <​code><​uses-permission android:​name="​android.permission.INTERNET"​ /></​code>​ <​code><​uses-permission android:​name="​android.permission.INTERNET"​ /></​code>​
Line 52: Line 51:
 <​code><​uses-permission android:​name="​android.permission.ACCESS_NETWORK_STATE"​ /></​code>​ <​code><​uses-permission android:​name="​android.permission.ACCESS_NETWORK_STATE"​ /></​code>​
  
-Our application should not cause indirect costs to the user so that’s why we need to check what type of network connection do we need for our request. In the code snippet below we are checking that we are connected on the WiFi in order to start our file download. 
  
-<​code>​ +If your app needs to check the network'​s state it can use the system service ​ConnectivityManager ​- [[https://​developer.android.com/​training/​basics/​network-ops/​reading-network-state|documentation examples]]
-    ​ConnectivityManager ​connectivityManager = +
-            (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);​ +
-    NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();​+
  
-    if (networkInfo != null && networkInfo.isConnected() &&​ +If your app needs to react to connectivity changes ​(e.gsend a file when the network becomes availableyou can use Android'​s job scheduling API called [[https://​developer.android.com/​topic/​libraries/​architecture/​workmanager|WorkManager]],​ since newer Android versions removed the system broadcast for connectivity changesHere's an example ​(scenario #3of how to use it: [[https://​medium.com/​ki-labs-engineering/​monitoring-wifi-connectivity-status-part-1-c5f4287dd57|example]].
-            networkInfo.getType(== ConnectivityManager.TYPE_WIFI &&  +
-            networkInfo.getType() != ConnectivityManager.TYPE_MOBILE)) { +
-        downloadFileTask.execute(fileUrl)+
-    } +
-</code>+
  
-/* THE NETWORKINFO STUFF IS DEPRECATED AND NEEDS TO BE CHANGED 
-*/ 
  
-<note important>​Note for Android 9 and above http calls will receive an IOException because cleartext network traffic is disabled. You can add your application trusted domains in a network security configuration file or to enable cleartext within the application manifest. Check [[https://​developer.android.com/​training/​articles/​security-config#​CleartextTrafficPermitted|Cleartext Traffic Permitted]]</​note>​+<note important>​Note for Android 9 and above HTTP calls will receive an IOException because cleartext network traffic is disabled. You can add your application trusted domains in a network security configuration file or to enable cleartext within the application manifest. Check [[https://​developer.android.com/​training/​articles/​security-config#​CleartextTrafficPermitted|Cleartext Traffic Permitted]]</​note>​
  
 ==== HttpsUrlConnection ==== ==== HttpsUrlConnection ====
Line 110: Line 98:
 As stated above in Retrofit we only need to declare our service interface. Below we declared our //​WeatherService//​ which has a //GET// request for the location weather. Retrofit uses [[https://​docs.oracle.com/​javase/​tutorial/​java/​annotations/​|Annotations]] to show how a request will be handled. In our case we simply defined in the GET request the path to the weather endpoint and the //​{location}//​ parameter using //{}//. In order to complete this we added the //​@Path("​location"​)//​ annotation before the location parameter. This way we link the method parameter to the URL parameter. ​ As stated above in Retrofit we only need to declare our service interface. Below we declared our //​WeatherService//​ which has a //GET// request for the location weather. Retrofit uses [[https://​docs.oracle.com/​javase/​tutorial/​java/​annotations/​|Annotations]] to show how a request will be handled. In our case we simply defined in the GET request the path to the weather endpoint and the //​{location}//​ parameter using //{}//. In order to complete this we added the //​@Path("​location"​)//​ annotation before the location parameter. This way we link the method parameter to the URL parameter. ​
  
-<code>+<coden java>
 public interface WeatherService { public interface WeatherService {
  @GET("/​api/​weather?​location={location}"​)  @GET("/​api/​weather?​location={location}"​)
Line 119: Line 107:
 From here the [[https://​square.github.io/​retrofit/​2.x/​retrofit/​retrofit2/​Retrofit.html|Retrofit]] class generates an implementation of the WeatherService interface. When creating the Retrofit instance we need to pass our //​baseUrl//​. Using this and appending the requests path will create the complete URL. From here the [[https://​square.github.io/​retrofit/​2.x/​retrofit/​retrofit2/​Retrofit.html|Retrofit]] class generates an implementation of the WeatherService interface. When creating the Retrofit instance we need to pass our //​baseUrl//​. Using this and appending the requests path will create the complete URL.
  
-<​code>​+<​code ​java>
 Retrofit retrofit = new Retrofit.Builder() Retrofit retrofit = new Retrofit.Builder()
  .baseUrl("​https://​my.weather.com/"​)  .baseUrl("​https://​my.weather.com/"​)
Line 129: Line 117:
 Using the service we can make the [[https://​square.github.io/​retrofit/​2.x/​retrofit/​retrofit2/​Call.html|Call]] that will make synchronous or asynchronous HTTP request to the remote webserver. Using the service we can make the [[https://​square.github.io/​retrofit/​2.x/​retrofit/​retrofit2/​Call.html|Call]] that will make synchronous or asynchronous HTTP request to the remote webserver.
  
-<​code>​+<​code ​java>
 Call<​Weather>​ weatherCall = service.getLocationWeather("​Bucharest"​);​ Call<​Weather>​ weatherCall = service.getLocationWeather("​Bucharest"​);​
 </​code>​ </​code>​
Line 135: Line 123:
 In order to make the call and get the result in our app will need to call [[https://​square.github.io/​retrofit/​2.x/​retrofit/​retrofit2/​Call.html#​enqueue-retrofit2.Callback-|enqueue()]]. This sends asynchronously the request and notifies the application through the //​onResponse()//​ callback when a response is received or through //​onFailure()//​ callback if something goes wrong. This call is handled on a background thread by Retrofit. ​ In order to make the call and get the result in our app will need to call [[https://​square.github.io/​retrofit/​2.x/​retrofit/​retrofit2/​Call.html#​enqueue-retrofit2.Callback-|enqueue()]]. This sends asynchronously the request and notifies the application through the //​onResponse()//​ callback when a response is received or through //​onFailure()//​ callback if something goes wrong. This call is handled on a background thread by Retrofit. ​
  
-<​code>​+<​code ​java>
 weatherCall.enqueue(new Callback<​Weather>​() { weatherCall.enqueue(new Callback<​Weather>​() {
  @Override  @Override
Line 149: Line 137:
 </​code>​ </​code>​
  
-If the service responds with [[https://​www.json.org/​|JSON]] objects, Retrofit can help deserialize them by using //​converters//​. A popular JSON library is [[https://​github.com/​google/​gson|GSON]]. ​This helps converting JSON responses into [[https://en.wikipedia.org/wiki/Plain_old_Java_object|POJO]]sIn order to use this we need to add a [[http://​square.github.io/​retrofit/​2.x/​converter-gson/​retrofit2/​converter/​gson/​GsonConverterFactory.html|GsonConvertorFactory]] when creating the service:+If the service responds with [[https://​www.json.org/​|JSON]] objects, Retrofit can help deserialize them by using //​converters//​. A popular JSON library ​for Java is [[https://​github.com/​google/​gson|GSON]]. ​If you are using Kotlin we recommend  
 +[[https://github.com/square/moshi|Moshi]]. 
  
-<​code>​+The GSON library helps you convert JSON responses into [[https://​en.wikipedia.org/​wiki/​Plain_old_Java_object|POJO]]s. In order to use this we need to add a [[http://​square.github.io/​retrofit/​2.x/​converter-gson/​retrofit2/​converter/​gson/​GsonConverterFactory.html|GsonConvertorFactory]] when creating the service: 
 + 
 +<​code ​java>
 Retrofit retrofit = new Retrofit.Builder() Retrofit retrofit = new Retrofit.Builder()
  .baseUrl("​https://​my.weather.com"​)  .baseUrl("​https://​my.weather.com"​)
Line 164: Line 155:
 <​code>​ <​code>​
 dependencies { dependencies {
-    implementation '​com.squareup.retrofit2:​retrofit:​2.5.0' +    implementation '​com.squareup.retrofit2:​retrofit:​2.9.0' 
-    implementation ​"com.squareup.retrofit2:converter-gson:2.5.0"+    implementation ​'com.google.code.gson:gson:2.8.6'
 } }
 </​code>​ </​code>​
  
 +If you plan to use Moshi, here's a Kotlin example (although Moshi supports Java too):
 +<code java>
 +val retrofit: Retrofit = Retrofit.Builder()
 +        .baseUrl("​https://​my.weather.com"​)
 +        .addConverterFactory(MoshiConverterFactory.create())
 +        .build()
 +</​code>​
 +<​code>​
 +apply plugin: '​kotlin-kapt'​
 +
 +dependencies {
 +    implementation '​com.squareup.retrofit2:​retrofit:​2.9.0'​
 +    implementation '​com.squareup.retrofit2:​converter-moshi:​2.9.0'​
 +    implementation '​com.squareup.moshi:​moshi-kotlin:​1.12.0'​
 +
 +    kapt "​com.squareup.moshi:​moshi-kotlin-codegen:​1.11.0"​
 +}
 +</​code>​
 +
 +<​note>​Kotlin example for retrofit on our lab's repo: [[https://​github.com/​SMD-UPB/​labs/​tree/​main/​lab5-demos/​retrofit-demo-kotlin|retrofit-demo-kotlin]]</​note>​
 ==== Tasks ==== ==== Tasks ====
  
 === Task 0 - Init === === Task 0 - Init ===
  
-Create a new Android application project. Download the lab archive and change ​the content of activity_main.xml and AndroidManifest.xml.+Create a new Android application project ​for API version >= Oreo 
 + 
 +Download the lab archive and replace ​the content of activity_main.xml and AndroidManifest.xml ​with the one provided in the archive.
  
 === Task 1 - Fetch web page through HTTP (3p) === === Task 1 - Fetch web page through HTTP (3p) ===
Line 192: Line 205:
 Update the code from Task 1 in order to use //​HttpsURLConnection//​. Add the WIFI connectivity check before making the call. Update the code from Task 1 in order to use //​HttpsURLConnection//​. Add the WIFI connectivity check before making the call.
  
-Try different websites using //http// or //https//. Are there any diferences?+Try different websites using //http// or //https//. Are there any differences?
  
 === Task 3 - Retrofit call (4p) ===  === Task 3 - Retrofit call (4p) === 
  
-Using the code examples from the lab change the HttpURLConnection network call with Retrofit implementation. The webpage URL will be set as a base URL for the Retrofit instance.+Using the code examples from the lab change the HttpURLConnection network call with Retrofit implementation. The webpage URL will be set as a base URL for the Retrofit instance.
  
 <note hint>Use @GET("​."​) for the service call.</​note>​ <note hint>Use @GET("​."​) for the service call.</​note>​
Line 204: Line 217:
  
 For this task will use the [[http://​open-notify.org/​Open-Notify-API/​|Open Notify]] API which gives information about the [[https://​en.wikipedia.org/​wiki/​International_Space_Station|ISS]]. For this task will use the [[http://​open-notify.org/​Open-Notify-API/​|Open Notify]] API which gives information about the [[https://​en.wikipedia.org/​wiki/​International_Space_Station|ISS]].
-From this API will use http://​api.open-notify.org/​astros.json which gives us the current number of people in space. Using the lab code examples create a Retrofit service for this URL. Make a call to get the number of people in space and return a POJO matching the JSON file structure. Make the request to the API and present ​in a TextView ​the current number of people in space.+From this API will use http://​api.open-notify.org/​astros.json which gives us the current number of people in space. Using the lab code examples create a Retrofit service for this URL. Make a call to get the number of people in space and return a POJO matching the JSON file structure. Make the request to the API and present the current number of people in space in a TextView.
  
 <note hint>The POJO object should contain only the attributes that we need in our application.</​note>​ <note hint>The POJO object should contain only the attributes that we need in our application.</​note>​
Line 215: Line 228:
 === Resources === === Resources ===
  
-{{:​smd:​laboratoare:​lab5_skel.zip|}}+   ​* ​{{:​smd:​laboratoare:​lab5_skel.zip|}} 
 +   * [[https://​github.com/​SMD-UPB/​labs/​tree/​main/​demos|Demo app for Retrofit shown during a lab]]
  
  
smd/laboratoare/05.1614534643.txt.gz · Last modified: 2021/02/28 19:50 by adriana.draghici
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0