Intro to Android Development
  • Welcome
  • Syllabus
  • Hack Challenge
  • Resources
    • Lecture Videos
    • Ed Discussion
    • Git & GitHub Help/How-To
    • Setting up Android Studio
    • Starting an Android Studio Project & Making an Emulator
    • Importing, Exporting, & Submitting Your Projects to CMS
  • SP25 Course Material
    • Week 1 | Course Logistics, Kotlin, & Basic UI
      • Relevant Links
      • Demo/Lecture: Eatery Card
      • A0: Eatery Card (Follow-Along)
    • Week 2 | States, Components, LazyColumn
      • Relevant Links
      • Demo: Todo List
      • A2: Shopping List
    • Week 3 | Navigation & Animations
      • Relevant Links
      • Demo: Onboarding
      • A3: Stock Trading (RobbingGood)
    • Week 4 | MVVM and Flows
      • Relevant Links
      • Demo: Eatery Card 2
      • A4: Chat of a Lifetime
    • Week 5 | Dumb Components & UIEvents
      • Relevant Links
      • Demo: Music Player
      • A5: Rate My Vibe
    • Week 6 | Coroutines, Networking, JSON
      • Relevant Links
      • Demo: Retrofit
      • A6: You Should Even Lift, Bro.
  • Bonus Week | Android Job Search
    • Relevant Links
    • Android Technical Interview Question!
  • Textbook
    • 1. Introduction to the Editor and Views
      • 1.1 Introduction to the Editor
      • 1.2 SDK Management
      • 1.3 Kotlin Overview
      • 1.4 Views
      • 1.5 Android Studio Project Demo + Understanding The Editor
    • 2. Jetpack Compose
      • 2.1 Introduction
      • 2.2 Layouts
      • 2.3 Modifiers
      • 2.4 Animations
      • 2.5 Lazy Lists
      • 2.6 Reactive UI
    • 3. Intents and Manifest
      • 3.1 Activities
      • 3.2 Implicit Intents
      • 3.3 Explicit Intents
      • 3.4 Manifest
      • 3.5 Permissions
      • 3.6 Summary
    • 4. Navigation
      • 4.1 Types of Navigation
      • 4.2 Implementation of the Bottom Navigation Bar
    • 5. Data and Persistent Storage
      • 5.1 Singleton Classes
      • 5.2 Shared Preferences
      • 5.3 Rooms
      • 5.4 Entities
      • 5.5 Data Access Objects
      • 5.6 Databases
    • 5.5 Concurrency
      • 5.5.1 Coroutines
      • 5.5.2 Implementation of Coroutines
      • 5.5.3 Coroutines with Networking Calls
    • 6. Networking and 3rd Party libraries
      • 6.1 HTTP Overview
      • 6.2 3rd Party Libraries
      • 6.3 JSON and Moshi
      • 6.4 Retrofit
      • 6.5 Summary
    • 7. MVVM Design Pattern
      • 7.1 Key Idea
      • 7.2 Implementation Ideas
    • 8. Flows
    • 9. The Art and Ontology of Software
    • 10. 🔥 Firebase
      • 10.1 Setting up Firebase
      • 10.2 Authentication
      • 10.3 Analytics
      • 10.4 Messaging
      • 10.5 Firestore
  • Additional Topics
    • Git and GitHub
    • Exporting to APK
  • Archive
    • Archived Native Android Textbook Pages
      • 1. Layouts and More Views
        • 1.1 File Structure and File Types
        • 1.2 Resource Files
        • 1.3 Button and Input Control
        • 1.4 ViewGroups
        • 1.5 Summary + A Note On Chapter 2 Topics
      • 2. RecyclerViews
        • 2.1 RecyclerViews
        • 2.2 RecyclerView Performance
        • 2.3 Implementation of a Recycler View
        • 2.4 Implementation with Input Controls
        • 2.5 Filtering RecyclerViews
        • 2.6 Recyclerview Demo
      • 3. ListViews and Searching
        • 3.1 ListView vs. RecyclerView
        • 3.2 ListView Performance
        • 3.3 Implementation of a ListView
        • 3.4 Searching in a List View
      • 4. Fragments
        • 4.1 What are Fragments?
        • 4.2 Lifecycle of a Fragment
        • 4.3 Integrating a Fragment into an Activity
        • 4.4 Sharing Data Between Fragments
        • 4.5 Fragment Slide Shows
      • 5. OkHttp
      • 6. Activity Lifecycle
      • 7. Implementation of Tab Layout
    • Fall 2024 Course Material
      • Lecture 1 & Exercise 1: Introduction to Android
      • Lecture 1.5: Beauty of Kotlin
      • Lecture 2 & HW 2: Modifiers, Lazylists and Reactive UI
      • Lecture 3 & HW 3: Animations, Intents and Manifest
      • Lecture 4 & HW 4: Coroutines & Navigation
      • Lecture 5 & HW 5: Persistent Storage, Networking, and JSON Parsing
      • Lecture 6 & HW 6: MVVM, Flows
      • Bonus Lectures & Bonus HW
      • Bonus Lecture: Industry Practice
    • Spring 2024 Course Material
      • Lecture 1 & Exercise 1: Introduction to Android
      • Lecture 4 & HW 4: LazyLists
      • Lecture 6 & HW 6: Networking, Data, and Persistent Storage
    • Spring 2020 Course Material
      • Week 1: Intro to the Editor
      • Week 2: Views and Layouts
      • Week 3: Intent and Manifest
      • Week 4: ListView and RecyclerView
      • Week 5: Fragments
      • Week 6: Networking
    • Spring 2021 Lecture & HW 8: Networking & 3rd Party APIs
    • HackOurCampus Workshop
Powered by GitBook
On this page
  • Using OkHttp
  • Setting up
  • GET
  • POST
  • Updating UI

Was this helpful?

  1. Archive
  2. Archived Native Android Textbook Pages

5. OkHttp

Previous4.5 Fragment Slide ShowsNext6. Activity Lifecycle

Last updated 7 months ago

Was this helpful?

is a third-party library developed by Square for sending and receive HTTP-based network requests.

Using OkHttp

Setting up

Add the following dependencies in your module-level build.gradle file:

// Plugins should be located at the very top of your file
apply plugin: 'kotlin-kapt'

// Alternative if your plugins look like this!
plugins {
   ...
   id 'kotlin-kapt' 
}

...

dependencies {
   // define a BOM and its version
   implementation(platform("com.squareup.okhttp3:okhttp-bom:4.9.3"))

   // define any required OkHttp artifacts without version
   implementation("com.squareup.okhttp3:okhttp")
   implementation("com.squareup.okhttp3:logging-interceptor")
}

In the case of OkHttp, we will need internet permissions.

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

GET

How can we execute GET requests using OkHttp? We can make an asynchronous GET call using the enqueue, which will tell us through the callback once the request has completed.

private val client = OkHttpClient()

fun run() {
    val request = Request.Builder()
        // URL given from API/Backend (make sure the URL + path
        // is corect for the given get request
        .url(...)
        // can also add headers with .addHeader e.g .addHeader("Authorization", "Bearer ${TOKEN}")
        .get()
        .build()
        

    client.newCall(request).enqueue(object : Callback {
        override fun onFailure(call: Call, e: java.io.IOException) {
            e.printStackTrace()
        }

        override fun onResponse(call: Call, response: Response) {
            if (!response.isSuccessful) {
                // Can also respond with some UI saying check internet, try again, network request failed, 
                // etc. as opposed to exception (which will crash your app unless caught)!
                throw IOException("Unexpected code $response")
            } else {
                // Can get access to the body with response.body(). Can then use
                // Moshi techniques to convert said body to a Kotlin object if applicable
                // or you can just parse the body directly!
                val body = response.body

                val blackjackHand = adapter.fromJson(body!!.source())

                val jsonObject = JSONObject(body.string())
                jsonObject.getString(KEY_NAME)
                jsonObject.getInt(KEY_NAME)
                ...
            }
        }
    })

POST

Post follows a very similar format to the GET request, except now we have to pass in some data into our request! There's lots of ways to do this depending on how the API wants the request to be formatted. Here we'll just showcase some examples that you can use to tailor to your needs:

private val client = OkHttpClient()

fun run() {
    val blackjackHand = BlackjackHand(
        Card('6', Suit.SPADES),
        listOf(Card('4', Suit.CLUBS), Card('A', Suit.HEARTS))
    )
    
    // If our request body is meant to be an object representative of some
    // class, we can leverage Moshi to help us build it.
    val moshi: Moshi = Moshi.Builder().build()
    val adapter: JsonAdapter<BlackjackHand> =
        moshi.adapter<BlackjackHand>(BlackjackHand::class.java)
    val json: String = adapter.toJson(blackjackHand)
    val requestBody = json.toRequestBody("application/json".toMediaTypeOrNull())

    // Alternative way of building a requestBody, directly 
    // setting the key/value pairs of the post body.
    val jsonObject = JSONObject().apply { 
        put("card", json)
    }
    val requestBody = jsonObject.toString().toRequestBody("application/json".toMediaTypeOrNull())
        
    val postRequest = Request.Builder()
        .post(requestBody)
        .url(...)
        // Can also add headers with .addHeader e.g .addHeader("Authorization", "Bearer ${TOKEN}")
        .build()

        
    client.newCall(postRequest).enqueue(object : Callback {
        override fun onFailure(call: Call, e: java.io.IOException) {
            e.printStackTrace()
        }

        override fun onResponse(call: Call, response: Response) {
            if (!response.isSuccessful) {
                // Can also respond with some UI saying check internet, try again, network request failed, 
                // etc. as opposed to exception (which will crash your app unless caught)!
                throw IOException("Unexpected code $response")
            } else {
                val body = response.body

                // Some APIs as a response to a POST request may return objects right back, 
                // which we can then use Moshi to convert to a Kotlin object if
                // we wish (like the imgur example above)
                val blackjackHand = adapter.fromJson(body!!.source())
                
                // Other times, APIs will return a sucess/failure boolean as a response,
                // so parsing directly may a better alternative!
                val jsonObject = JSONObject(body.string())
                jsonObject.getString(KEY_NAME)
                jsonObject.getInt(KEY_NAME)
                ...
            }
        }
    })
}

Updating UI

The callbacks for OkHttp (methods like onFailure and onResponse) run on a background thread. If you want to immediately process something in the UI you will need to do your updates on the UI thread (which is the main, single thread that all Android applications run on).

The recommended way to do this is using the Android Jetpack architectural components of ViewModel and LiveData. The advantage of using these components is that they persist through Activity lifecycle changes so for example when the device orientation changes and the Activity is recreated, ViewModel and LiveData will persist and the information is reused in the created activity. Both of these components arise in discussions about app architecture in Android, which is outside the scope of this class.

For now, you can utilize the method runOnUiThread, which is usually executed within a worker thread to update UI:

client.newCall(postRequest).enqueue(object : Callback {
    override fun onFailure(call: Call, e: java.io.IOException) {
        e.printStackTrace()
    }

    override fun onResponse(call: Call, response: Response) {
        runOnUiThread {
            // Any UI updates here, e.g. creating Adapters, updating text, etc.
            textView.text = response.body!!.string()
        }
    }
})

See Android's if you are interested in learning more!

OkHttp
guide to app architecture