Read JSON files From Android Assets Folder using Kotlin
In this Android Kotlin tutorial, we will explore how to read JSON files from Android assets folder?
Create new Android Kotlin Project in Android Studio (Flamingo)
Add the following dependencies to build.gradle(:app)
// Kotlin coroutines
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
// AndroidX lifecycle components
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.6.1"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.1"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1"
// RecyclerView
implementation "androidx.recyclerview:recyclerview:1.3.0"
Sync the project
Switch your current Android project to Project view
Create new folder in Project > app > src > main > assets [right click > New > Directory] Name the new directory as json.
Place the following files to json directory of assets
user1.json
{
"name": "Nikin",
"age": 67,
"email": "abc@bigknol.com",
"isSubscriber": true
}
user2.json
{
"name": "Jacky",
"age": 45,
"email": "abcd@bigknol.com",
"isSubscriber": false
}
Add a RecyclerView to activity_main.xml file
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
android:background="@android:color/white"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:scrollbars="vertical"
tools:listitem="@layout/item_user" />
</RelativeLayout>
Let’s create a class called ‘User’. This data class to represent the structure of the JSON data. In your Kotlin file (e.g., User.kt), define the data class as follows:
package com.bigknol.simple.jsonandroid
data class User(
val name: String,
val age: Int,
val email: String,
val isSubscriber: Boolean
)
To show the items in a recycler view, we need to have an adapter and a layout to show details from the JSON files (user1,json, user2.json)
item_user.xml (Place this file inside the layout folder)
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/nameTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"/>
<TextView
android:id="@+id/ageTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/emailTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/subsTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="italic"/>
</LinearLayout>
Let’s create an adapter class for RecyclerView
UserAdapter.kt
package com.bigknol.simple.jsonandroid
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
class UserAdapter(private val userList: List<User>) :
RecyclerView.Adapter<UserAdapter.UserViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_user, parent, false)
return UserViewHolder(view)
}
override fun onBindViewHolder(holder: UserAdapter.UserViewHolder, position: Int) {
val user = userList[position]
holder.bind(user)
}
override fun getItemCount(): Int {
return userList.size
}
class UserViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
{
private val nameTextView : TextView =itemView.findViewById(R.id.nameTextView)
private val ageTextView : TextView =itemView.findViewById(R.id.ageTextView)
private val emailTextView : TextView =itemView.findViewById(R.id.emailTextView)
private val subscribeTextView : TextView =itemView.findViewById(R.id.subsTextView)
fun bind(user: User)
{
nameTextView.text = user.name
ageTextView.text = user.age.toString()
emailTextView.text = user.email
subscribeTextView.text = if (user.isSubscriber) "Subscriber of BigKnol" else "Not a subscriber of BigKnol"
}
}
}
How to fetch JSON files from Android assets folder ?
MainActivity.kt
How to get a list of all the json files from assets/json folder?
val jsonFiles = assets.list("json")
Let’s parse each json file and convert them into user objects:
Parse the JSON data using the JSONObject class. In your activity or fragment, you can do the following:
val userList = mutableListOf<User>()
jsonFiles?.forEach { fileName ->
val jsonString =
assets.open("json/$fileName").bufferedReader().use { it.readText() }
val jsonObject = JSONObject(jsonString)
val user = User(
name = jsonObject.getString("name"),
age = jsonObject.getInt("age"),
email = jsonObject.getString("email"),
isSubscriber = jsonObject.getBoolean("isSubscriber")
)
userList.add(user)
// Update the UI with the list of users
launch(Dispatchers.Main)
{
showUserList(userList)
}
}
In this example, we create a User object by parsing the JSON data using the JSONObject class and then accessing the values using the appropriate methods (getString, getInt, getBoolean).
MainActivity.kt (Complete)
package com.bigknol.simple.jsonandroid
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.json.JSONObject
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
lifecycleScope.launch(Dispatchers.IO) {
// get a list of JSON file names from the assets folder
val jsonFiles = assets.list("json")
// Parse each json file and convert them into user objects
val userList = mutableListOf<User>()
jsonFiles?.forEach { fileName ->
val jsonString =
assets.open("json/$fileName").bufferedReader().use { it.readText() }
val jsonObject = JSONObject(jsonString)
val user = User(
name = jsonObject.getString("name"),
age = jsonObject.getInt("age"),
email = jsonObject.getString("email"),
isSubscriber = jsonObject.getBoolean("isSubscriber")
)
userList.add(user)
// Update the UI with the list of users
launch(Dispatchers.Main)
{
showUserList(userList)
}
}
}
}
private fun showUserList(userList: List<User>) {
// Use the userList to populate the RecyclerView
val recyclerView: RecyclerView = findViewById(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = UserAdapter(userList)
}
}
The correct approach for managing coroutines in Android is to use structured concurrency and tie the coroutines to a specific CoroutineScope that corresponds to the lifecycle of the relevant Android component. For example, you can use lifecycleScope for coroutines tied to an Activity or Fragment, or viewModelScope for coroutines tied to a ViewModel.
How does this app look like ?
Please note that in a real Android app, you might get the JSON data from a server or an API call, rather than hardcoding it as a string like we did here. Additionally, for more complex JSON parsing scenarios, you might want to consider using libraries like Gson or Moshi, which can simplify the parsing process.