androidjsonkotlinretrofit

How to make API call in Kotlin Using Retrofit (Android) with nested JSON APIs


The below code is working fine and I am able to fetch data from it. But I want to do the same with a different API here is the API: https://dl.dropboxusercontent.com/s/p57gxwqm84zkp96/demo_api.json . I am new to APIs and I don't know how to fetch data from this API. Can someone please help and explain how to do it?

NOTE: I have made data classes of this second API using the "Kotlin Data class file from JSON" plugin.

## activity_main.xml ##

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/txtDesc"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/textview"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

## MainActivity.kt ##

package com.example.apiproject

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.TextView
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

const val BASE_URL = "https://jsonplaceholder.typicode.com/"

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        getMyData();
    }

    private fun getMyData() {
        val retrofitBuilder = Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl(BASE_URL)
            .build()
            .create(APIInterface::class.java)

        val retrofitData = retrofitBuilder.getData()

        retrofitData.enqueue(object : Callback<List<MyDataItem>?> {
            override fun onResponse(call: Call<List<MyDataItem>?>, response: Response<List<MyDataItem>?>) {
                val responseBody = response.body()!!

                val myStringBuilder  = StringBuilder()
                for (myData in responseBody){
                    myStringBuilder.append(myData.id)
                    myStringBuilder.append("\n")
                }
                val textView = findViewById<TextView>(R.id.txtDesc)
                textView.text = myStringBuilder
            }

            override fun onFailure(call: Call<List<MyDataItem>?>, t: Throwable) {
                Log.d("MainActivity","OnFailure: "+t.message)
            }
        })
    }
}

## APIInterface.kt ##

package com.example.apiproject

import retrofit2.Call
import retrofit2.http.GET

interface APIInterface {
    @GET("posts")
    fun getData(): Call<List<MyDataItem>>
}

## MyDataItem.kt ##

package com.example.apiproject

data class MyDataItem(
    val body: String,
    val id: Int,
    val title: String,
    val userId: Int
)

## APIInterface.kt ##

package com.example.apiproject

class MyData : ArrayList<MyDataItem>()

Solution

  • The way you organized your project structure, I followed you for presentational purposes.

    activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
    <TextView
        android:id="@+id/tvTextView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:layout_marginStart="10dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    The URL you provided for that I used two data class

    Status.kt

    data class Status(
        val Message: String,
        val RecordCount: String,
        val Result: List<Result>,
        val Status: Int
    )
    

    Result.kt

    data class Result(
        val CategName: String,
        val CurrencySymbol: String,
        val DealCategoryID: String,
        val DealID: String,
        val DealType: String,
        val Description: String,
        val Discount: String,
        val Image: String,
        val MemberTier: String,
        val PromoCode: String,
        val StoreID: String,
        val StoreName: String,
        val TOC: String,
        val Title: String,
        val TowerNumber: String,
        val ValidityEnd: String,
        val ValidityStart: String,
        val isFav: String
    )
    

    APIInterface.kt

    interface APIInterface {
        @GET("demo_api.json")
        fun getData() : Call<Status>
    }
    

    MainActivity.kt

    class MainActivity : AppCompatActivity() {
        val BASE_URL = "https://dl.dropboxusercontent.com/s/p57gxwqm84zkp96/"
        private val TAG = "MainActivity"
        private lateinit var textView: TextView
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            textView = findViewById(R.id.tvTextView)
            getMyData()
        }
    
        private fun getMyData() {
            val retrofitBuilder = Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl(BASE_URL)
                .build()
                .create(APIInterface::class.java)
    
            val retrofitData = retrofitBuilder.getData()
            retrofitData.enqueue(object : Callback<Status> {
                override fun onResponse(call: Call<Status>, response: Response<Status>) {
                    val responseBody = response.body()!!
                    Log.d("Message ", responseBody.Message)
                    Log.d("RecordCount ", responseBody.RecordCount)
                    Log.d("Status ", responseBody.Status.toString())
    
    
                    for (i in 0 until responseBody.Result.size) {
                        Log.d("CategName ", responseBody.Result[i].CategName)
                        Log.d("CurrencySymbol ", responseBody.Result[i].CurrencySymbol)
                        Log.d("DealCategoryID ", responseBody.Result[i].DealCategoryID)
                        Log.d("DealID ", responseBody.Result[i].DealID)
                        Log.d("Description ", responseBody.Result[i].DealType)
                        Log.d("Description ", responseBody.Result[i].Description)
                        Log.d("Discount ", responseBody.Result[i].Discount)
                        Log.d("Image ", responseBody.Result[i].Image)
                        Log.d("MemberTier ", responseBody.Result[i].MemberTier)
                        Log.d("PromoCode ", responseBody.Result[i].PromoCode)
                        Log.d("StoreID ", responseBody.Result[i].StoreID)
                        Log.d("StoreName ", responseBody.Result[i].StoreName)
                        Log.d("TOC ", responseBody.Result[i].TOC)
                        Log.d("Title ", responseBody.Result[i].Title)
                        Log.d("TowerNumber ", responseBody.Result[i].TowerNumber)
                        Log.d("ValidityEnd ", responseBody.Result[i].ValidityEnd)
                        Log.d("ValidityStart ", responseBody.Result[i].ValidityStart)
                        Log.d("isFav ", responseBody.Result[i].isFav + "\n\n")
                    }
    
                }
    
                override fun onFailure(call: Call<Status>, t: Throwable) {
                    Log.d(TAG, "OnFailure: " + t.message)
    
                }
    
            }
            )
        }
    }
    

    For presentation purposes I used Logcat. It will be best if you can use recyclerview..