Skip to content

Commit 305278f

Browse files
Further improvements.
1 parent 4752519 commit 305278f

File tree

4 files changed

+33
-28
lines changed

4 files changed

+33
-28
lines changed

content/learning-paths/smartphones-and-mobile/build-android-selfie-app-using-mediapipe-multimodality/6-flow-data-to-view-1.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ layout: learningpathall
99

1010
[SharedFlow](https://developer.android.com/kotlin/flow/stateflow-and-sharedflow#sharedflow) and [StateFlow](https://developer.android.com/kotlin/flow/stateflow-and-sharedflow#stateflow) are [Kotlin Flow](https://developer.android.com/kotlin/flow) APIs that enable Flows to optimally emit state updates and emit values to multiple consumers.
1111

12-
In this Learning Path, you will experiment with both `SharedFlow` and `StateFlow`. This section focuses on SharedFlow, and the section focuses on StateFlow.
12+
In this Learning Path, you will experiment with both `SharedFlow` and `StateFlow`. This section focuses on SharedFlow, and the next section focuses on StateFlow.
1313

1414
`SharedFlow` is a general-purpose, hot flow that can emit values to multiple subscribers. It is highly configurable, allowing you to configure settings such as the replay cache size and buffer capacity.
1515

@@ -366,5 +366,5 @@ class GestureOverlayView(context: Context?, attrs: AttributeSet?) :
366366

367367
4. Build and run the app again. Now you should see face and gesture overlays on top of the camera preview as shown below. Good job!
368368

369-
![overlay views](images/6/overlay%20views.png)
369+
![overlay views alt-text#center](images/6/overlay%20views.png "Figure 7: Face and Gesture Overlays.")
370370

content/learning-paths/smartphones-and-mobile/build-android-selfie-app-using-mediapipe-multimodality/7-flow-data-to-view-2.md

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ weight: 7
66
layout: learningpathall
77
---
88

9-
`StateFlow` is a subclass of SharedFlow and internally use a SharedFlow to manage its emissions. However, it provides a stricter API, ensuring that:
9+
`StateFlow` is a subclass of `SharedFlow` and internally uses `SharedFlow` to manage its emissions. However, it provides a stricter API, ensuring that:
1010
1. It always has an initial value.
1111
2. It emits only the latest state.
1212
3. It cannot configure its replay cache (always `1`).
@@ -15,7 +15,7 @@ Therefore, `StateFlow` is a specialized type of `SharedFlow` that represents a s
1515

1616
## Expose UI states in StateFlow
1717

18-
1. Expose two `StateFlow`s named `faceOk` and `gestureOk` in `MainViewModel`, indicating whether the subject's face and gesture are ready for a selfie.
18+
1. Expose two `StateFlow`s named `faceOk` and `gestureOk` in `MainViewModel`, indicating whether the subject's face and gestures are ready for a selfie.
1919

2020
```kotlin
2121
private val _faceOk = MutableStateFlow(false)
@@ -25,14 +25,14 @@ Therefore, `StateFlow` is a specialized type of `SharedFlow` that represents a s
2525
val gestureOk: StateFlow<Boolean> = _gestureOk
2626
```
2727

28-
2. Append the following constant values to `MainViewModel`'s companion object. In this demo app, you will focus on smiling faces and thumb-up gestures.
28+
2. In this demo app, you will focus on smiling faces and thumb-up gestures. Append the following constant values to `MainViewModel`'s companion object:
2929

3030
```kotlin
3131
private const val FACE_CATEGORY_MOUTH_SMILE = "mouthSmile"
3232
private const val GESTURE_CATEGORY_THUMB_UP = "Thumb_Up"
3333
```
3434

35-
3. Update `onFaceLandmarkerResults` and `onGestureResults` to check if their corresponding results are meeting the conditions above.
35+
3. Update `onFaceLandmarkerResults` and `onGestureResults` to check if their corresponding results are meeting the conditions above:
3636

3737
```kotlin
3838
override fun onFaceLandmarkerResults(resultBundle: FaceResultBundle) {
@@ -75,7 +75,7 @@ Therefore, `StateFlow` is a specialized type of `SharedFlow` that represents a s
7575
<string name="condition_indicator_text_gesture">Gesture</string>
7676
```
7777

78-
2. In the same directory, create a new resource file named `dimens.xml` if it does not exist. This file is used to define layout related dimension values:
78+
2. In the same directory, create a new resource file named `dimens.xml` if it does not exist already. This file is used to define layout related dimension values:
7979

8080
```xml
8181
<?xml version="1.0" encoding="utf-8"?>
@@ -85,7 +85,7 @@ Therefore, `StateFlow` is a specialized type of `SharedFlow` that represents a s
8585
</resources>
8686
```
8787

88-
3. Navigate to `activity_main.xml` layout file and add the following code to the root `ConstraintLayout`. Add this code after the two overlay views which you just added in the previous section.
88+
3. Navigate to the `activity_main.xml` layout file and add the following code to the root `ConstraintLayout`. Add this code after the two overlay views which you have just added in the previous section:
8989

9090
```xml
9191
<androidx.appcompat.widget.SwitchCompat
@@ -111,7 +111,9 @@ Therefore, `StateFlow` is a specialized type of `SharedFlow` that represents a s
111111
app:layout_constraintBottom_toBottomOf="parent" />
112112
```
113113

114-
4. Finally, navigate to `MainActivity.kt` and append the following code inside `repeatOnLifecycle(Lifecycle.State.RESUMED)` block, after the `launch` block you just added in the previous section. This makes sure each of the three parallel `launch` run in its own co-routine concurrently without blocking each other.
114+
4. Finally, navigate to `MainActivity.kt` and append the following code inside the `repeatOnLifecycle(Lifecycle.State.RESUMED)` block, after the `launch` block.
115+
116+
This makes sure each of the three parallel `launch` code sections run in its own co-routine concurrently without blocking each other.
115117

116118
```kotlin
117119
launch {
@@ -127,20 +129,21 @@ Therefore, `StateFlow` is a specialized type of `SharedFlow` that represents a s
127129
}
128130
```
129131

130-
5. Build and run the app again. Now you should see two switches on the bottom of the screen as shown below, which turn on and off while you smile and show thumb-up gestures. Good job!
132+
5. Build and run the app again.
133+
Now you should see two switches on the bottom of the screen as shown below, which turn on and off while you smile and show thumb-up gestures. Good job!
131134

132135
![indicator UI](images/7/indicator%20ui.png)
133136

134137
## Recap on SharedFlow vs StateFlow
135138

136-
This app uses `SharedFlow` for dispatching overlay views' UI events without mandating a specific stateful model, which avoids redundant computation. Meanwhile, it uses `StateFlow` for dispatching condition switches' UI states, which prevents duplicated emission and consequent UI updates.
139+
This app uses `SharedFlow` for dispatching overlay views' UI events without mandating a specific stateful model, which avoids redundant computation. Meanwhile, it uses `StateFlow` for dispatching condition switches' UI states, which prevents duplicate emission and consequent UI updates.
137140

138-
Here's a overview of the differences between `SharedFlow` and `StateFlow`:
141+
Here is an overview of the differences between `SharedFlow` and `StateFlow`:
139142

140143
| | SharedFlow | StateFlow |
141144
| --- | --- | --- |
142-
| Type of Data | Transient events or actions | State or continuously changing data |
145+
| Type of Data | Transient events or actions | State or continuously-changing data |
143146
| Initial Value | Not required | Required |
144-
| Replays to New Subscribers | Configurable with replay (e.g., 0, 1, or more) | Always emits the latest value |
147+
| Replays to New Subscribers | Configurable with replay (for example, 0, 1, or more) | Always emits the latest value |
145148
| Default Behavior | Emits only future values unless replay is set | Retains and emits only the current state |
146-
| Use Case Examples | Short-lived, one-off events that shouldn't persist as part of the state | Long-lived state that represents the current view's state |
149+
| Use Case Examples | Short-lived, one-off events that should not persist as part of the state | Long-lived state that represents the state of the current view |

content/learning-paths/smartphones-and-mobile/build-android-selfie-app-using-mediapipe-multimodality/8-mediate-flows.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ weight: 8
66
layout: learningpathall
77
---
88

9-
Now you have two independent Flows indicating the conditions of face landmark detection and gesture recognition. The simplest multimodality strategy is to combine multiple source Flows into a single output Flow, which emits consolidated values as the single source of truth for its observers (collectors) to carry out corresponding actions.
9+
Now you have two independent Flows indicating the conditions of face landmark detection and gesture recognition.
10+
11+
The simplest multimodality strategy is to combine multiple source Flows into a single output Flow, which emits consolidated values as the single source of truth for its observers, the collectors, to carry out corresponding actions.
1012

1113
## Combine two Flows into a single Flow
1214

13-
1. Navigate to `MainViewModel` and append the following constant values to its companion object.
15+
1. Navigate to `MainViewModel` and append the following constant values to its companion object:
1416

1517
* The first constant defines how frequently you sample the conditions from each Flow.
1618

@@ -39,7 +41,7 @@ You might need to add the `@OptIn(FlowPreview::class)` annotation as `sample` is
3941

4042
{{% /notice %}}
4143

42-
3. Expose a `SharedFlow` variable which emits a `Unit` whenever the face and gesture conditions are met and stay stable for a while, which means `500`ms as defined above. Again, add `@OptIn(FlowPreview::class)` if needed.
44+
3. Expose a `SharedFlow` variable which emits a `Unit` whenever the face and gesture conditions are met and stays stable for a while, which means `500`ms as defined above. Again, add `@OptIn(FlowPreview::class)` if required.
4345

4446
```kotlin
4547
val captureEvents: SharedFlow<Unit> = _bothOk
@@ -138,13 +140,11 @@ You can also opt to use `SharedFlow<Boolean>` and remove the `map { }` operation
138140
}
139141
}
140142
```
141-
4. Even though the photo capture has already been implemented, it is still quite inconvenient to check out the logs afterwards to find out whether the photo capture has been successfully executed.
142-
143-
You can now add a flash effect UI to explicitly show the users that a photo has been captured.
143+
4. Even though the photo capture has already been implemented, it is still inconvenient to check out the logs afterwards to find out whether the photo capture has been successfully executed, so you can now add a flash effect UI to explicitly show the users that a photo has been captured.
144144

145145
## Add a flash effect upon capturing photo
146146

147-
1. Navigate to the `activity_main.xml` layout file and insert the following `View` element between the two overlay views and the two `SwitchCompat` views. This is essentially just a white blank view covering the whole surface.
147+
1. Navigate to the `activity_main.xml` layout file and insert the following `View` element between the two overlay views and the two `SwitchCompat` views. This is essentially just a white blank view covering the whole surface:
148148

149149
```
150150
<View
@@ -187,6 +187,6 @@ You can now add a flash effect UI to explicitly show the users that a photo has
187187

188188
4. Build and run the app:
189189

190-
* Try keeping up a smiling face while presenting thumb-up gestures.
190+
* Try to maintain a smiling face whilst also presenting thumb-up gestures.
191191
* When you see both switches, turn on and stay stable for approximately half a second.
192-
* The screen should flash white and then a photo should be captured and show up in your album, which might take a few seconds depending on your Android device's hardware. Good job!
192+
* The screen should flash white and then a photo should be captured. This will show up in your album, which might take a few seconds depending on your Android device's hardware. Good job!

content/learning-paths/smartphones-and-mobile/build-android-selfie-app-using-mediapipe-multimodality/9-avoid-redundant-requests.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ weight: 9
66
layout: learningpathall
77
---
88

9-
So far you have implemented the core logic for MediaPipe's face and gesture task results and photo capture execution. However, the view controller is not communicating its execution results back to the view model, which raises the risk for photo capture failures, frequent or duplicate requests, and other potential issues.
9+
So far you have implemented the core logic for MediaPipe's face and gesture task results and photo capture execution.
10+
11+
However, the view controller is not communicating its execution results back to the view model, which raises the risk for photo capture failures, frequent or duplicate requests, and other potential issues.
1012

1113
### Introduce camera readiness state
1214

@@ -54,11 +56,11 @@ Copy in the following:
5456
```
5557

5658

57-
## Introduce camera cooldown
59+
## Introduce a camera cooldown mechanism
5860

5961
The differences in hardware mean that the duration of an image capture varies across Android devices. Additionally, consecutive image captures place a heavy load on the CPU, GPU, camera, and flash memory buffer.
6062

61-
To address this, you can implement a simple cooldown mechanism after each photo capture that can enhance the user experience while conserving computing resources.
63+
To address this, you can implement a simple cooldown mechanism after each photo capture that can both enhance the user experience whilst also conserving computing resources.
6264

6365
1. Add the following constant value to `MainViewModel`'s companion object. This defines a three-second cooldown before making the camera available again.
6466

@@ -91,7 +93,7 @@ However, silently failing without notifying the user is not a good practice for
9193

9294
{{% /notice %}}
9395

94-
## Entire sample code on GitHub
96+
## Further resource for support: entire sample code on GitHub
9597

9698
If you run into any difficulties completing this Learning Path, you can check out the [complete sample code](https://github.com/hanyin-arm/sample-android-selfie-app-using-mediapipe-multimodality) and import it into Android Studio.
9799

0 commit comments

Comments
 (0)