Skip to content

First-time Playing with Jetpack Compose (Rambling my Thoughts)

Last week, Jetpack Compose Beta was officially released. Everybody and their mothers knows that Compose is gonna make a huge shift in the Android system, arguably even to the scale that Kotlin did when it took over Java as the primary language of Android.

Jetpack Compose is a new UI toolkit being developed for Android that gets rid of all the XML and replaces it with declarative Kotlin APIs, with the goal at hand being a faster and easier way to build our apps’ UI.

Since the initial alpha release of Compose, the Beta release now has these features:

  • 🆕 Coroutines support
  • 🆕 Accessibility support for Talkback – support for other technologies will be in Stable
  • 🆕 Easy to use Animations, with a completely new API since alpha.
  • Interoperability with Views
  • Material UI Components, all with @Sampled code
  • Lazy Lists – Jetpack Compose’s take on RecyclerView
  • DSL-based Constraint Layout
  • Modifiers
  • Testing
  • Theming and Graphics, with easy support for Dark and Light mode
  • Input and gestures
  • Text and editable text
  • Window management

On top of this, the beta release also means that Compose is API complete (has all the features required to build a production app) as well as API stable (no more changing or removing APIs).

Jetpack Compose 1.0 is set to release later this year, which means that it is my recommendation that every Android Developer out there starts spending a bit of time learning Compose, because this will undeniably become a key skill for each and every Android Dev to have in their toolbelt.

Trying it out

Just know that this section isn’t a tutorial or really an informative post. The facts may not even be accurate. Just me rambling my thoughts.

Right now, I’m quite new to Jetpack Compose. I’ve not really played around with it before the Beta release. Just looking at it on the surface however, there’s much that looks promising about it.

@Composable
fun HomeScreen() {
    StackUsersComposeTheme {
        Surface(color = MaterialTheme.colors.background) {
            val users: List<User> by viewModel.usersLiveData.observeAsState(listOf())
            UsersList(users)
        }
    }
}

Having Kotlin-based UI code means that it immediately becomes more testable, and there are specific Compose testing libraries that help us with this.

We no longer have to deal with the pain and boilerplate of RecyclerViews and such because these are oversimplified in Compose.

I’m sure these are just a few examples of what makes Compose great, but the learning curve may be an interesting one.

We have so many defined patterns for building our apps’ UI the way we currently do. An example of such is having a single activity with multiple fragments and using Jetpack Navigation to move around them.

Although Compose has its own version of NavGraph and such, I haven’t found a way to fully implement it without going into XML a little bit.

Is this even the right way to think about it though? The samples apps say differently.

The sample apps seem to drop the idea of fragments and instead adopt the idea of ‘Screens’.

Forget even having more than a single activity OR fragment when you can just replace the root composable (compose function) that draws your entire screen.

@Suppress("DEPRECATION") // allow ViewModelLifecycleScope call
@Composable
fun ArticleScreen(
    postId: String,
    postsRepository: PostsRepository,
    onBack: () -> Unit
) {
    val (post) = produceUiState(postsRepository, postId) {
        getPost(postId)
    }
    // TODO: handle errors when the repository is capable of creating them
    val postData = post.value.data ?: return

    // [collectAsState] will automatically collect a Flow<T> and return a State<T> object that
    // updates whenever the Flow emits a value. Collection is cancelled when [collectAsState] is
    // removed from the composition tree.
    val favorites by postsRepository.observeFavorites().collectAsState(setOf())
    val isFavorite = favorites.contains(postId)

    // Returns a [CoroutineScope] that is scoped to the lifecycle of [ArticleScreen]. When this
    // screen is removed from composition, the scope will be cancelled.
    val coroutineScope = rememberCoroutineScope()

    ArticleScreen(
        post = postData,
        onBack = onBack,
        isFavorite = isFavorite,
        onToggleFavorite = {
            coroutineScope.launch { postsRepository.toggleFavorite(postId) }
        }
    )
}

A snippet from the JetNews sample

Each Screen talks directly to the repository to get the data they need to display. Wait so are we also dropping the idea of ViewModels?

I don’t want to make it sounds like I dislike the change. In fact, I think it’s quite cool that each individual view has the ability to observe data directly from things like LiveData or Flow.

val users: List<User> by viewModel.usersLiveData.observeAsState(listOf())

Snippet from my app StackUsersCompose

Admittedly though, I don’t know enough to make any conclusions about how these patterns should be defined. There are too many questions I have that I can’t answer yet myself.

For example: it’s cool that a Screen can make easy direct use of repositories, but isn’t the point of the ViewModel to separate business logic from the View? But with Compose, will we even need to separate that logic the same way we do now?

I suppose these are answers that I will be able to give a better answer as I personally get a bit more experience with Compose, but now that it’s been released in beta and is API complete and stable, the community will undoubtedly be understanding the best patterns and practices to develop efficiently with Compose.

I know I said that the shift to Compose is arguably a change on the same scale as the Kotlin transition, but I dare say it may be even bigger than that. Kotlin changed the language we based our development on, but the general patterns we followed stayed the same for the most part.

With Compose, we may have to reconsider how we build the entire presentation layer of our app.

Anyway those are my first impressions on Jetpack Compose. I very much welcome the change and am looking forward to its 1.0 release later this year.

I have played around with it already a little bit with my new StackUsersCompose app that I’ve got now on Github. I attempted to use the single-activity-many-fragments pattern with Compose as much as I can, but like I said earlier, I had to involve a little XML there.

Who knows what I’ll do with that app moving forward though. I’ve set it up as a playground for myself to really learn Compose, so it’s built complete with Dagger and such, with a simple repository that queries users from StackOverflow using its public API.

If you can’t tell, I queried “Tim”

At the time of writing this post, I’ve done hardly anything on the Compose side of things, other than show a list of the users I did query, but I think the fact that I was able to make this list in literally no time at all speaks volumes about the kind of power that Compose has.

I will be doing more posts about Compose moving forward. There’s plenty I want to try out, so if you have any ideas you’d like to see, stick it down in the comments. Till then, happy coding ༼ つ ◕_◕ ༽つ

Tags: