DEV Community ๐Ÿ‘ฉโ€๐Ÿ’ป๐Ÿ‘จโ€๐Ÿ’ป

DEV Community ๐Ÿ‘ฉโ€๐Ÿ’ป๐Ÿ‘จโ€๐Ÿ’ป is a community of 968,873 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Cover image for Jetpack Compose API Data to List View
Paul Allies
Paul Allies

Posted on

Jetpack Compose API Data to List View

Many times we need to make API calls to fetch data and display that data using a List. Here, I show how to do that with Compose. To illustrate the structure of the application letโ€™s look at the following diagram

Firstly, Add Internet Permission to your Application in AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"></uses-permission>
Enter fullscreen mode Exit fullscreen mode

Before we start letโ€™s update our build.gradle file with the Retrofit HTTP client and aConverter which uses Gson for serialisation to and from JSON.:

dependencies{
...
implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.retrofit2:converter-gson:2.0.0"
}
Enter fullscreen mode Exit fullscreen mode

The Todo APIService

We need to create the Retrofit instance to send the network requests. we need to use the Retrofit Builder class and specify the base URL for the service. Here we have one GET to fetch all Todos and deserialise to List

data class Todo(
    var userId: Int,
    var id: Int,
    var title: String,
    var completed: Boolean
)

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

interface APIService {
    @GET("todos")
    suspend fun getTodos(): List<Todo>

    companion object {
        var apiService: APIService? = null
        fun getInstance(): APIService {
            if (apiService == null) {
                apiService = Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build().create(APIService::class.java)
            }
            return apiService!!
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

The Todo ViewModel

The View model publishes the todoList and has a getTodoList function for the view to use to fetch all todos

class TodoViewModel : ViewModel() {
    private val _todoList = mutableStateListOf<Todo>()
    var errorMessage: String by mutableStateOf("")
    val todoList: List<Todo>
        get() = _todoList

    fun getTodoList() {
        viewModelScope.launch {
            val apiService = APIService.getInstance()
            try {
                _todoList.clear()
                _todoList.addAll(apiService.getTodos())

            } catch (e: Exception) {
                errorMessage = e.message.toString()
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

The Todo View

Finally we have the view which watches the ViewModel for any todo list state changes. The todo list is display in the view. On Launch the view makes the api call.

class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        val vm = TodoViewModel()
        super.onCreate(savedInstanceState)
        setContent {
            MaterialTheme {
                TodoView(vm)
            }
        }
    }
}

@Composable
fun TodoView(vm: TodoViewModel) {

    LaunchedEffect(Unit, block = {
        vm.getTodoList()
    })

    Scaffold(
        topBar = {
            TopAppBar(
                title = {
                    Row {
                        Text("Todos")
                    }
                })
        },
        content = {
            if (vm.errorMessage.isEmpty()) {
                Column(modifier = Modifier.padding(16.dp)) {
                    LazyColumn(modifier = Modifier.fillMaxHeight()) {
                        items(vm.todoList) { todo ->
                            Column {
                                Row(
                                    modifier = Modifier
                                        .fillMaxWidth()
                                        .padding(16.dp),
                                    horizontalArrangement = Arrangement.SpaceBetween
                                ) {
                                    Box(
                                        modifier = Modifier
                                            .fillMaxWidth()
                                            .padding(0.dp, 0.dp, 16.dp, 0.dp)
                                    ) {
                                        Text(
                                            todo.title,
                                            maxLines = 1,
                                            overflow = TextOverflow.Ellipsis
                                        )
                                    }
                                    Spacer(modifier = Modifier.width(16.dp))
                                    Checkbox(checked = todo.completed, onCheckedChange = null)
                                }
                                Divider()
                            }
                        }
                    }
                }
            } else {
                Text(vm.errorMessage)
            }
        }
    )
}
Enter fullscreen mode Exit fullscreen mode

Image description

Top comments (0)

๐ŸŒš Friends don't let friends browse without dark mode.

Sorry, it's true.