Search code examples
androidjsonkotlinandroid-jetpack-composedeserialization

How to read and decode a remote JSON data in Jetpack Compose app?


By placing the JSON file locally in src/main/assets folder you can easily access its content to deserialize it (I used .decodeFromString() method here). However, it's not clear how to deserialize a remote JSON data in Jetpack Compose app.

For example, a data located at the address https://api.opendota.com/api/heroStats or at the address https://restcountries.com/v3.1/all.

Here's a code with a local JSON parsing:

@Serializable
data class Root(val tenants: List<Tenant>)

@Serializable
data class Tenant(val name: String, val room: Int)

@Composable
fun DecodedText() {
    var text: String by remember { mutableStateOf("") }
    val context = LocalContext.current

    LaunchedEffect(Unit) {
        val json = readJsonFromAssets(context = context, fileName = "sample.json")
        val decoded = Json.decodeFromString<Root>(json).tenants

        for (i in decoded.indices) {
            text += decoded[i].name + " – "
            text += decoded[i].room.toString() + "\n"
        }
    }
    Text(
        text = text,
        fontWeight = FontWeight.Black,
        fontSize = 22.sp,
        modifier = Modifier.padding(50.dp)
    )
}
fun readJsonFromAssets(context: Context, fileName: String): String {
    return context.assets.open(fileName).bufferedReader().use { it.readText() }
}

I'd like to know how to do this using the kotlin serialization plugin. Any help appreciated.


Solution

  • After carefully studying this issue, I came to the following solution. I tried to parse JSON data using both web addresses, both examples are decoded fine, for my answer I've chosen the second address. Here's my code:

    typealias Countries = List<Country>
    
    private val jsonPty = Json {
        ignoreUnknownKeys = true
    }
    @Serializable
    data class Country(
        val name: Names
    )
    @Serializable
    data class Names(
        val common: String,
        val official: String
    )
    

    @ExperimentalSerializationApi
    @Composable
    fun RemoteDecodedText() {
        val url = URL("https://restcountries.com/v3.1/all")
        var json: String by remember { mutableStateOf("") }
        var parsedJson: String by remember { mutableStateOf("") }
        val scope = CoroutineScope(Dispatchers.Default)
    
        LaunchedEffect(Unit) {
            scope.launch {
                json = url.openStream().use {
                    it.readAllBytes().decodeToString()
                }
                parsedJson = jsonPty.decodeFromString<Countries>(json)[64].name.official
            }
        }
        Text(
            text = "Location: $parsedJson",
            fontSize = 20.sp,
            fontWeight = FontWeight.Black,
            modifier = Modifier.padding(60.dp)
        )
    }
    

    Result (index=64) :

    // Location: Kingdom of Morocco