Skip to content

Commit 2ab716d

Browse files
authored
Merge pull request #675 from square/ray/non-null-parent
Truth in advertising: findParentLifecycle cannot return null
2 parents bb98bdb + d9155c4 commit 2ab716d

File tree

3 files changed

+16
-25
lines changed

3 files changed

+16
-25
lines changed

workflow-ui/container-android/src/main/java/com/squareup/workflow1/ui/modal/ModalContainer.kt

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ public abstract class ModalContainer<ModalRenderingT : Any> @JvmOverloads constr
4848
* this container's modals. Only valid after the the view has been attached.
4949
*/
5050
private val parentLifecycleOwner by lazy(mode = LazyThreadSafetyMode.NONE) {
51-
WorkflowLifecycleOwner.get(this)
51+
WorkflowLifecycleOwner.get(this) ?: error(
52+
"Expected to find either a ViewTreeLifecycleOwner in the view tree, or for the " +
53+
"context to be a LifecycleOwner, in $this"
54+
)
5255
}
5356

5457
/**
@@ -83,7 +86,7 @@ public abstract class ModalContainer<ModalRenderingT : Any> @JvmOverloads constr
8386
// any, and so we can use our lifecycle to destroy-on-detach the dialog hierarchy.
8487
WorkflowLifecycleOwner.installOn(
8588
dialogView,
86-
findParentLifecycle = { parentLifecycleOwner?.lifecycle }
89+
findParentLifecycle = { parentLifecycleOwner.lifecycle }
8790
)
8891
// Ensure that each dialog has its own ViewTreeSavedStateRegistryOwner,
8992
// so views in each dialog layer don't clash with other layers.
@@ -101,10 +104,11 @@ public abstract class ModalContainer<ModalRenderingT : Any> @JvmOverloads constr
101104
override fun onViewAttachedToWindow(v: View) {
102105
// Note this is a different lifecycle than the WorkflowLifecycleOwner – it will
103106
// probably be the owning AppCompatActivity.
104-
lifecycle = parentLifecycleOwner?.lifecycle
105-
// Android makes a lot of logcat noise if it has to close the window for us. :/
106-
// https://github.com/square/workflow/issues/51
107-
lifecycle?.addObserver(dismissOnDestroy)
107+
lifecycle = parentLifecycleOwner.lifecycle.also {
108+
// Android makes a lot of logcat noise if it has to close the window for us. :/
109+
// https://github.com/square/workflow/issues/51
110+
it.addObserver(dismissOnDestroy)
111+
}
108112
}
109113

110114
override fun onViewDetachedFromWindow(v: View) {

workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/androidx/WorkflowLifecycleOwner.kt

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public interface WorkflowLifecycleOwner : LifecycleOwner {
7474
*/
7575
public fun installOn(
7676
view: View,
77-
findParentLifecycle: (View) -> Lifecycle? = { v -> findParentViewTreeLifecycle(v) }
77+
findParentLifecycle: (View) -> Lifecycle = { v -> findParentViewTreeLifecycle(v) }
7878
) {
7979
RealWorkflowLifecycleOwner(findParentLifecycle).also {
8080
ViewTreeLifecycleOwner.set(view, it)
@@ -90,9 +90,10 @@ public interface WorkflowLifecycleOwner : LifecycleOwner {
9090
public fun get(view: View): WorkflowLifecycleOwner? =
9191
ViewTreeLifecycleOwner.get(view) as? WorkflowLifecycleOwner
9292

93-
private fun findParentViewTreeLifecycle(view: View): Lifecycle? {
93+
private fun findParentViewTreeLifecycle(view: View): Lifecycle {
9494
// Start at our view's parent – if we look on our own view, we'll just get this back.
9595
return (view.parent as? View)?.let(::lifecycleOwnerFromViewTreeOrContextOrNull)?.lifecycle
96+
?: error("Expected parent or context of $view to have or be a ViewTreeLifecycleOwner")
9697
}
9798
}
9899
}
@@ -105,7 +106,7 @@ public interface WorkflowLifecycleOwner : LifecycleOwner {
105106
@OptIn(WorkflowUiExperimentalApi::class)
106107
@VisibleForTesting(otherwise = PRIVATE)
107108
internal class RealWorkflowLifecycleOwner(
108-
private val findParentLifecycle: (View) -> Lifecycle?,
109+
private val findParentLifecycle: (View) -> Lifecycle,
109110
enforceMainThread: Boolean = true,
110111
) : WorkflowLifecycleOwner,
111112
LifecycleOwner,
@@ -157,10 +158,7 @@ internal class RealWorkflowLifecycleOwner(
157158

158159
// Always check for a new parent, in case we're attached to different part of the view tree.
159160
val oldLifecycle = parentLifecycle
160-
parentLifecycle = checkNotNull(findParentLifecycle(v)) {
161-
"Expected to find either a ViewTreeLifecycleOwner in the view tree, or for the view's" +
162-
" context to be a LifecycleOwner."
163-
}
161+
parentLifecycle = findParentLifecycle(v)
164162

165163
if (parentLifecycle !== oldLifecycle) {
166164
oldLifecycle?.removeObserver(this)

workflow-ui/core-android/src/test/java/com/squareup/workflow1/ui/androidx/RealWorkflowLifecycleOwnerTest.kt

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import org.junit.Test
1717
import org.mockito.kotlin.doReturn
1818
import org.mockito.kotlin.mock
1919
import org.mockito.kotlin.whenever
20-
import kotlin.test.assertFailsWith
2120

2221
internal class RealWorkflowLifecycleOwnerTest {
2322

@@ -28,23 +27,13 @@ internal class RealWorkflowLifecycleOwnerTest {
2827
private var parentLifecycle: LifecycleRegistry? = null
2928
private val owner = RealWorkflowLifecycleOwner(
3029
enforceMainThread = false,
31-
findParentLifecycle = { parentLifecycle }
30+
findParentLifecycle = { parentLifecycle!! }
3231
)
3332

3433
@Test fun `lifecycle starts initialized`() {
3534
assertThat(owner.lifecycle.currentState).isEqualTo(INITIALIZED)
3635
}
3736

38-
@Test fun `attach throws when no parent lifecycle found`() {
39-
val error = assertFailsWith<IllegalStateException> {
40-
makeViewAttached()
41-
}
42-
assertThat(error.message).isEqualTo(
43-
"Expected to find either a ViewTreeLifecycleOwner in the view tree, or for the" +
44-
" view's context to be a LifecycleOwner."
45-
)
46-
}
47-
4837
@Test fun `lifecycle not destroyed when detached`() {
4938
ensureParentLifecycle()
5039
makeViewAttached()

0 commit comments

Comments
 (0)