Overview
Time to bring live data into our UI.
In this lesson, we will:
- Update our Jetpack Compose code to render launch data from the query we wrote
- Display a list of launches in a LazyColumn
Set up the LaunchList
composable
In this section, we'll be looking at LaunchList.kt
. In that module, we will declare a list of LaunchListQuery.Launch
types, initialized as empty:
@Composablefun LaunchList(onLaunchClick: (launchId: String) -> Unit) {var launchList by remember { mutableStateOf(emptyList<LaunchListQuery.Launch>()) }LaunchedEffect(Unit) {// ...
LaunchListQuery.Launch
is a typesafe generated model from your LaunchList.graphql
query.
Make a UI for the launch items
Further down in the file, find the LaunchItem
composable. We will pass it a LaunchListQuery.Launch
and display the id:
@Composableprivate fun LaunchItem(launch: LaunchListQuery.Launch, onClick: (launchId: String) -> Unit) {ListItem(modifier = Modifier.clickable { onClick(launch.id) },headlineContent = {// Mission nameText(text = "Launch ${launch.id}")},
Use the data in the list
Fill launchList
with the data from the response, and use it in the LazyColumn
:
@Composablefun LaunchList(onLaunchClick: (launchId: String) -> Unit) {var launchList by remember { mutableStateOf(emptyList<LaunchListQuery.Launch>()) }LaunchedEffect(Unit) {val response = apolloClient.query(LaunchListQuery()).execute()launchList = response.data?.launches?.launches?.filterNotNull() ?: emptyList()}LazyColumn {items(launchList) { launch ->LaunchItem(launch = launch, onClick = onLaunchClick)}}}
You can remove the Log.d
invocation as part of this step. You will also need to import some extension functions.
About nullability
You may have noticed that we are using .filterNotNull()
in the above code snippet. That is necessary because the schema for our GraphQL service defines launches
as a list of nullable Launch
objects:
type LaunchConnection {launches: [Launch]!}
In GraphQL, all fields are nullable by default. Fields annotated with !
are non-null. This syntax can be a little confusing with lists, especially since there's an exclamation !
in the expression. Here's a little guide:
launches: [Launch] # `launches` can be null, and each list element can be nulllaunches: [Launch!]! # `launches` cannot be null, and each list element cannot be nulllaunches: [Launch!] # `launches` can be null, but if it's not, each list element cannot be nulllaunches: [Launch]! # `launches` cannot be null, but each list element can be null
So in our app, the schema tells us that launches
will always be a list, and each element within that list will be a Launch
object or null
. Apollo Kotlin translates that logic from GraphQL to Kotlin via code generation. We don't want to show null
to our users, though, which is why we filter those items out of our array.
Test your query
Hit the Run button. You now have a UI connected to your GraphQL queries 🚀
Practice
!
) next to a field in a GraphQL schema signify?Up next
Showing our basic launch details is only the beginning. Next up, let's supplement our query with a few more fields.
Share your questions and comments about this lesson
This course is currently in
You'll need a GitHub account to post below. Don't have one? Post in our Odyssey forum instead.