Skip to content

Fixed resumed child when parent is not resumed #65

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Nov 16, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Lifecycle documentation enhancement
  • Loading branch information
i.karenkov committed Nov 16, 2024
commit 1e006fcfff74faed9ac71cbac8ecb71e2081b7ed
150 changes: 50 additions & 100 deletions Writerside/topics/Lifecycle.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
# Lifecycle

This article covers the lifetime of screen instances and their integration with Android Lifecycle.
This article covers the lifetime of screen instances and their integration with the Android Lifecycle.

## Screen instance lifecycle
## Screen Instance Lifecycle

It is guaranteed that the screen instance lifetime is equal to application (process) lifetime, when you provide Modo integration using built-in
function from `Modo`, such as`Modo.rememberRootScreen`. No matter how many times a screen is recomposed, activity or/and fragment is recreated etc.
The lifetime of a screen instance is guaranteed to match the application (process) lifetime when you integrate Modo using built-in functions such as
`Modo.rememberRootScreen`. Regardless of how many times a screen is recomposed, or whether the activity and/or fragment is recreated, the screen
instance remains consistent. This allows you to safely inject the screen instance into your DI container.

## Android Lifecycle
## Android Lifecycle Integration

Modo provides Android Lifecycle integration for your screens.
You can use `LocalLifecycleOwner` inside `Screen.Content` to access the lifecycle of a screen.
It will return the nearest Screen's lifecycle owner.
Modo provides seamless [integration](%github_code_url%/modo-compose/src/main/java/com/github/terrakok/modo/android/ModoScreenAndroidAdapter.kt)
with a Android Lifecycle for your screens.

You can use `LocalLifecycleOwner` inside `Screen.Content` to access the lifecycle of a screen. This will return the nearest screen's lifecycle owner.

```kotlin
class SampleScreen : Screen {
Expand All @@ -22,98 +24,46 @@ class SampleScreen : Screen {
}
```

### Lifecycle states and events

Let's take a look at what specific lifecycle states mean in the context of Screen Lifecycle:

<table>
<tr>
<th>State</th>
<th>Meaning</th>
</tr>
<tr>
<td><b>INITIALIZED</b></td>
<td>Screen is constructed (instance created), but it has never been displayed.</td>
</tr>
<tr>
<td><b>CREATED</b></td>
<td>

Screen is in navigation hierarchy, it can be reached from RootScreen, that is integrated to Activity/Fragment. With other words, it was displayed at
least once.

</td>
</tr>
<tr>
<td><b>STARTED</b></td>
<td>

`Screen.Content` is in composition.

</td>
</tr>
<tr>
<td><b>RESUMED</b></td>
<td>

**STARTED** and there is no unfinished transitions for this screen or it's parent.
</td>
</tr>
<tr>
<td><b>DESTROYED</b></td>
<td>Screen is removed from the navigation graph.</td>
</tr>
</table>

To clarify, let's take a look at the lifecycle events:

* `ON_CREATE` and `ON_DESTROY` are dispatched once per screen instance.

### Screen transitions and lifecycle

Modo provides convenient way to determine whenever screen's appearing/disappearing transitions are started or finished. To observe these events, you
can rely on `ON_RESUME` and `ON_PAUSE` lifecycle events, check out the table

<table>
<tr>
<th>Event</th>
<th>With transition</th>
<th>Without transition</th>
</tr>
<tr>
<td><b>ON_RESUME</b></td>
<td>

Dispatched when as soon as there are no unfinished transitions for this screen and parent is in `State.RESUMED`.
</td>
<td>

Parent is `RESUMED`
</td>
</tr>
<tr>
<td><b>ON_PAUSE</b></td>
<td>
Dispatched when hiding transition is started.
</td>
<td>

Dispatched right before `ON_STOP`.
</td>
</tr>
</table>

### Parent-Child Lifecycle propagation

There is a set of rules between lifecycle of parent and child screens, which allows you to relay on your screen's lifecycle and don't worry about
parent's lifecycle:

1. Screen's `Lifecycle.State` is always lower or equal (<=) than the state of its parent.
2. If child's lifecycle is ready to be in `RESUMED` state, it is not resumed until parent's lifecycle is `RESUMED` too.
3. When screen`s lifecycle is moved down, it also moves children lifecycle to the same state.
4. When screen's lifecycle is `RESUMED` and children's lifecycle is ready to be resumed, children's lifecycle is resumed too.

Practical example of this is using events `ON_RESUME` and `ON_PAUSE` to show and hide keyboard:
### Lifecycle States and Events

Here’s an overview of lifecycle states and their meanings in the context of the screen lifecycle:

| **State** | **Meaning** |
|-----------------|-----------------------------------------------------------------------------------------------------------------------------|
| **INITIALIZED** | The screen is constructed (instance created) but has never been displayed. |
| **CREATED** | The screen is in the navigation hierarchy and can be reached from the `RootScreen` integrated with an Activity or Fragment. |
| **STARTED** | `Screen.Content` is in composition. |
| **RESUMED** | The screen is **STARTED**, and there are no unfinished transitions for this screen or its parent. |
| **DESTROYED** | The screen is removed from the navigation graph. |

> `ON_CREATE` and `ON_DESTROY` are dispatched once per screen instance.

### Screen Transitions and Lifecycle

Modo provides a convenient way to track when screen transitions start and finish. These events are tied to the `ON_RESUME` and `ON_PAUSE` lifecycle
events. Here’s a summary:

| **Event** | **With Transition** | **Without Transition** |
|---------------|------------------------------------------------------------------------------------------------|---------------------------------------------|
| **ON_RESUME** | Dispatched when there are no unfinished transitions, and the parent is in the `RESUMED` state. | Dispatched when the parent is in `RESUMED`. |
| **ON_PAUSE** | Dispatched when a hiding transition starts. | Dispatched immediately before `ON_STOP`. |

### Parent-Child Lifecycle Propagation

The lifecycle of parent and child screens follows a set of rules, ensuring consistency and predictability:

1. A screen's `Lifecycle.State` is always less than or equal to (`<=`) its parent's state.
2. A child screen is not moved to the `RESUMED` state until its parent is also in the `RESUMED` state.
3. When a screen's lifecycle state is downgraded, its child screens are also moved to the same state.
4. When a screen reaches the `RESUMED` state and its child screens are ready to resume, the children's lifecycles are also moved to `RESUMED`.

### Practical Example: Keyboard Management

A practical use case for these lifecycle events is managing the keyboard. For example, you can show and hide the keyboard using `ON_RESUME` and
`ON_PAUSE` events:

* `ON_RESUME` indicates that the screen is ready for user input (transitions are finished)
* `ON_PAUSE` indicates that the screen is not ready for user input (transitions are starting)

```kotlin
val lifecycleOwner = LocalLifecycleOwner.current
Expand Down