Open menu with table of contents Android Networking
Logo of Stuttgart Media University for light theme Logo of Stuttgart Media University for dark theme
Android Development

Android Networking

Stuttgart Media University

1 Agenda

  • Movie Tracker App
    • REST API Basics
    • JSON
    • Retrofit API client
    • GSON JSON converter
    • Retrofit Example
    • Image loading with Glide

2 REST API Basic

  • Representational state transfer
  • HTTP based
  • Predefined set of operations GET, POST, PUT, DELETE, PATCH, HEAD, CONNECT, OPTIONS and TRACE.
  • Formatted payload HTML, XML, JSON
  • Textual representation of web resources
  • Communication between client and server is stateless

3 Relationship between URI and HTTP methods

HTTP METHODS Collection resource, such as https://api.example.com/collection/ Member resource, such as https://api.example.com/collection/item3
GET Retrieve the URIs of the member resources of the collection resource in the response body. Retrieve representation of the member resource in the response body.
POST Create a member resource in the collection resource using the instructions in the request body. The URI of the created member resource is automatically assigned and returned in the response Location header field. Create a member resource in the member resource using the instructions in the request body. The URI of the created member resource is automatically assigned and returned in the response Location header field.
PUT Replace all the representations of the member resources of the collection resource with the representation in the request body, or create the collection resource if it does not exist. Replace all the representations of the member resource or create the member resource if it does not exist, with the representation in the request body.
PATCH Update all the representations of the member resources of the collection resource using the instructions in the request body, or may create the collection resource if it does not exist. Update all the representations of the member resource, or may create the member resource if it does not exist, using the instructions in the request body.
DELETE Delete all the representations of the member resources of the collection resource. Delete all the representations of the member resource.

Source: https://en.wikipedia.org/wiki/Representational_state_transfer (11/2019)

4 HTTP response status codes

  • Indicates what happen with a specific http request
  • 100–199 Informational responses
  • 200–299 Successful responses
  • 300–399 Redirects
  • 400–499 Client errors
  • 500–599 Server errors

5 JSON Basics

  • JavaScript Object Notation
  • Human readable
  • Standard data format
  • "Replacement of XML"
  • media type: application/json

6 JSON Data Types

  • object
  • array
  • null
  • string
  • boolean
  • number

For examples visit https://restfulapi.net/json-data-types/

7 JSON Example

{
   "Search":[
      {
         "Title":"I, Robot",
         "Year":"2004",
         "imdbID":"tt0343818",
         "Type":"movie",
         "Poster":"https://m.media-amazon.com/images/M/MV5BNmE1OWI2ZGItMDUyOS00MmU5LWE0MzUtYTQ0YzA1YTE5MGYxXkEyXkFqcGdeQXVyMDM5ODIyNw@@._V1_SX300.jpg"
      },
      {
         "Title":"Robot Revolution: The Making of 'I, Robot'",
         "Year":"2004",
         "imdbID":"tt0427788",
         "Type":"movie",
         "Poster":"N/A"
      },
      {
         "Title":"Day Out of Days: The 'I, Robot' Production Diaries",
         "Year":"2004",
         "imdbID":"tt0457853",
         "Type":"movie",
         "Poster":"N/A"
      },
   ],
   "totalResults":"3",
   "Response":"True"
}

8 REST API Clients

  • Best practice: Don't start implementing APIs before you understand them
  • It´s hard to test and debug API calls on Android (Multithreading, Log Cat, Debugger, Permissions, etc.)
  • Use API clients to understand how an API works
    • Browser
    • Browser Extensions like JSON Formatter
    • Broken JSON structure can and will break your client
    • Desktop Apps like POSTMAN

9 Retrofit

Link: https://square.github.io/retrofit/

  • Converts a HTTP API into a Java Interface
  • Minimum Requirements: Android 2.3.
  • Extensible via interceptors
  • Offers converters for all kind of API formats (JSON, XML, etc.)
  • Licensed under the Apache License, Version 2.0
  • Helps you with:
    • API definition
    • API parameters
    • Multithreading
    • Success and error handling
    • Converting JSON <--> Java

10 GSON

Link: https://github.com/google/gson

Gson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object. Gson can work with arbitrary Java objects including pre-existing objects that you do not have source-code of. There are a few open-source projects that can convert Java objects to JSON. However, most of them require that you place Java annotations in your classes; something that you can not do if you do not have access to the source-code. Most also do not fully support the use of Java Generics. Gson considers both of these as very important design goals.

10.1 Goals

  • Provide simple toJson() and fromJson() methods to convert Java objects to JSON and vice-versa
  • Allow pre-existing unmodifiable objects to be converted to and from JSON
  • Extensive support of Java Generics
  • Allow custom representations for objects
  • Support arbitrarily complex objects (with deep inheritance hierarchies and extensive use of generic types)

Source: https://github.com/google/gson (11/2019)

11 Retrofit Example

  1. Setup app Gradle dependency

Add retrofit and gson converter dependency to Gradle

implementation("com.squareup.retrofit2:converter-gson:2.9.0")
implementation("com.squareup.retrofit2:retrofit:2.9.0")

12 Retrofit Example

  1. Create Data Transfer Object (DTO) to represent API model

JSON:

{
    "Title": "Ghost in the Shell",
    "Year": "1995",
    "imdbID": "tt0113568",
    "Type": "movie",
    "Poster": "https://m.media-amazon.com/images/M/MV5BYWRiYjQyOGItNzQ1Mi00MGI1LWE3NjItNTg1ZDQwNjUwNDM2XkEyXkFqcGdeQXVyNTAyODkwOQ@@._V1_SX300.jpg"
}

Kotlin Class:

data class MovieDTO (
  val imdbID: String,
  val Title: String,
  val Year: String,
  val Poster: String
)

13 Retrofit Example

  1. Create DTO to represent API array

JSON:

{
"Search": [
    {
        "Title": "Ghost in the Shell",
        "Year": "2017",
        "imdbID": "tt1219827",
        "Type": "movie",
        "Poster": "https://m.media-amazon.com/images/M/MV5BMzJiNTI3MjItMGJiMy00YzA1LTg2MTItZmE1ZmRhOWQ0NGY1XkEyXkFqcGdeQXVyOTk4MTM0NQ@@._V1_SX300.jpg"
    },
    {
        "Title": "Ghost in the Shell",
        "Year": "1995",
        "imdbID": "tt0113568",
        "Type": "movie",
        "Poster": "https://m.media-amazon.com/images/M/MV5BYWRiYjQyOGItNzQ1Mi00MGI1LWE3NjItNTg1ZDQwNjUwNDM2XkEyXkFqcGdeQXVyNTAyODkwOQ@@._V1_SX300.jpg"
    }
    ]
}

Java Class:

class SearchResponse (
  var Search: List<MovieDTO>
)

14 Retrofit Example

  1. Create API Interface for Retrofit
interface MovieApi {
  @GET(".")
  suspend fun getSearchResult(
    @Query("s") movieSearch: String,
    @Query("apikey") apiKey: String
  ): SearchResponse
}

15 Retrofit Example

  1. Initialize GSON + Retrofit and make an API call
val data = ArrayList<MovieDTO>()

val gson = GsonBuilder().setLenient().create()

val retrofit = Retrofit.Builder().baseUrl("https://www.omdbapi.com/")
    .addConverterFactory(GsonConverterFactory.create(gson))
    .build()

val movieApi = retrofit.create(MovieApi::class.java)

val searchString = "Ghost in the Shell"

lifecycleScope.launch(Dispatchers.IO) {
  try {
    val body = movieApi.getSearchResult(searchString, "MySecretApiKey")
    data.addAll(body.search.map { return@map it.toDomain() })
  } catch ( e : Exception ) {
    Log.e("Oh noo.", e.message)
  }
}

We use the public free API from OMDb API for this example. You need to put in your email to get a private API key.

16 Image loading with Glide

  • Glide helps you to downlaod, cache and display images via standard Android ImageView.
  • Covers UI and background thread handling.
  • Allows to listen for success and error handling.
  • Extensible to allow usage of transformation (ex. round corners) and animations.
  • Glide v4 requires a minimum API level of 14.
  • Glide v4 requires you to compile against API 26 or later.
  • Allows integration into OkHttp. This is helpful if you hare authentication cookies between API calls and image loading calls.
  • Very important for using image loading with RecyclerViews since user can scroll while images are loaded.

17 Glide gradle dependencies

Add this dependency to your app build.gradle

implementation("com.github.bumptech.glide:glide:4.11.0")
ksp("com.github.bumptech.glide:compiler:4.11.0")

18 Glide basic usage

Load an remote image into a ImageView.

  • Create a new activty with a ImageView.

Layout XML

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/imgView"
        android:layout_width="200dp"
        android:layout_height="wrap_content" />
</LinearLayout>

19 Glide basic usage

Load an remote image into a ImageView.

  • Implement Glide

Activity

val imgUrl = "https://m.media-amazon.com/images/M/MV5BOTlhYTVkMDktYzIyNC00NzlkLTlmN2ItOGEyMWQ4OTA2NDdmXkEyXkFqcGdeQXVyNTAyODkwOQ@@._V1_SX300.jpg";
val imageView = findViewById(R.id.imgView)

Glide.with(this).load(imgUrl).into(imageView)

20 Glide basic usage

Load an remote image into a ImageView.

  • Implement Glide

center

21 Glide error & success handling

Glide allows for listening to success and error states. This allows you to handle broken urls or to post process images.

Example show Toast if Glide is unable to show image

val imgUrl = "https://m.media-amazon.com/images/M/MV5BOTlhYTVkMDktYzIyNC00NzlkLTlmN2ItOGEyMWQ4OTA2NDdmXkEyXkFqcGdeQXVyNTAyODkwOQ@@._V1_SX300.jpg";
val imageView = findViewById(R.id.imgView)

Glide.with(this).load(imgUrl).listener(object : RequestListener<Drawable?> {
  override fun onLoadFailed(
    e: GlideException?,
    model: Any?,
    target: Target<Drawable?>?,
    isFirstResource: Boolean
  ): Boolean {
    Log.e("TAG", "Error loading image", e)
    return false
  }

  override fun onResourceReady(
    resource: Drawable?,
    model: Any?,
    target: Target<Drawable?>?,
    dataSource: DataSource?,
    isFirstResource: Boolean
  ): Boolean {
    return false
  }
}).into(imageView)