Re-gaining orientation #2
Tags: android, kotlin, jetpackcompose
Published: 2021-03-21 13:10:30

Welcome to the second part of my series about screen orientation in Jetpack Compose. Please recall that at the end of the first installment I presented the following code snippet to you:

```kotlin
override fun onBackPressed() {
  if (isTwoColumnMode)
    super.onBackPressed()
  else {
    if (module.value == null)
      super.onBackPressed()
    else
      module.value = null
  }
}
```

Its purpose is to do whatever the framework wishes to do if the app is in two-column mode, but to just remove a currently visible composable if the app is not. Two-column mode in my example meant:

- show a list of modules on the left hand side of the screen
- show a module (a composable) in the bigger remaining part of the screen to the right of the list

If we only have one column, the app either shows

- a list of modules
- a module

Once you click on a list item, the list (composable) is replaced by the module (composable). If the user is done working with the module, the list needs to re-appear.

Now, although the app works as intended, I wrote:

> But this looks weird. This looks hacky.

It does.

Since the first Android version the back stack nicely represented a flow of activities. With Honeycomb the framework learned about fragments. And they were nicely integrated in the back stack, too (through fragment transactions).

With Jetpack Compose we are encouraged to no longer use fragments. This makes our lives easier, because fragments have a lifecycle similar to activities (which may at times feel complex and hard to grasp). On the other hand, because fragments have a lifecycle, you can react to *Hey fragment, you have been attached to an activity.* or *Hey fragment, you will be removed shortly, so get your stuff done*. This comes in handy for showing or hiding parts of the user interface, or, navigation.

Composables are just ui building blocks. They should be kept as simple as possible. The less logic they have the better. So they certainly follow no lifecycle similar to activities or fragments. If a composable is to be shown on screen is **declared** by the developer. This works well in many cases, but what about navigation-like changes?

*Jetpack Navigation* contains the artifact `navigation-compose` which is at the time of writing 1.0.0-alpha09. To use it in your app just add

```groovy
implementation "androidx.navigation:navigation-compose:1.0.0-alpha09"
```

to your *build.gradle* file.

You can then navigate between composables while taking advantage of the Navigation component’s infrastructure and features. [The docs say](https://developer.android.com/jetpack/compose/navigation) that `NavController`...

> is the central API for the Navigation component. It is
> stateful and keeps track of the back stack of composables
> that make up the screens in your app and the state of each
> screen.

To create one, invoke `rememberNavController()`.

```Kotlin
val navController = rememberNavController()
```

The docs continue:

> You should create the `NavController` in the place in your
> composable hierarchy where all composables that need to
> reference it have access to it.

So, what does this mean? In a typical two column situation there is no need to **navigate**. Please recall that my example from the first installment needed the hack regarding `onBackPressed()` only in portrait mode. Consequently I use Compose Navigation only there. In fact, we just need to change one composable:

```kotlin
@Composable
fun Portrait(module: MutableState<Module?>) {
  val navController = rememberNavController()
  NavHost(navController, startDestination = "moduleSelection") {
    composable("moduleSelection") {
      ModuleSelectionList(
        modules,
        callback = {
          module.value = it
          navController.navigate("module")
        }
      )
    }
    composable("module") {
      module.value?.let {
        Module(it)
      }
    }
  }
}

```

> Each `NavController` must be associated with a single
> `NavHost` composable. The `NavHost` links the
> `NavController` with a navigation graph that specifies the 
> composable destinations that you should be able to navigate
> between. As you navigate between composables, the content
> of the `NavHost` is automatically recomposed. 

As you can see, I need just two routes, `moduleSelection` (which is also the initial destination) and `module`. The module to be shown is passed to my `Portrait()` composable as a `MutableState<Module?>`, so it can be easily modified. All other parts, including the distinction between portrait and landscape, remain unchanged. Just remember how simple this is:

```kotlin
isTwoColumnMode = (LocalConfiguration.current.orientation
    == Configuration.ORIENTATION_LANDSCAPE)
if (isTwoColumnMode)
  Landscape(module)
else
  Portrait(module)
```

That's all for today. Please stay tuned for the third installment where I will be focussing an optimizing the screen layout for foldables.

---

[Source](https://github.com/tkuenneth/android-demos/tree/master/compose/ScreenSizeDemo)