Skip to content
Permalink
Browse files

Add new setContentWithLifecycle

Allows us to automatically dispose of the composition
once the lifecycle has been destroyed. Very useful
for fragments, with viewLifecycleOwner
  • Loading branch information
chrisbanes committed Jan 29, 2020
1 parent 58db881 commit 25ff426a264220ebb12784d3b320b3eb24bb8903
@@ -0,0 +1,45 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package app.tivi.common.compose

import android.view.ViewGroup
import androidx.compose.Composable
import androidx.compose.Composition
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.ui.core.setContent

/**
* A version of [ViewGroup.setContent], which accepts a [LifecycleOwner] to automatically
* dispose of the [Composition] once destroyed.
*/
fun ViewGroup.setContentWithLifecycle(
lifecycle: LifecycleOwner,
content: @Composable() () -> Unit
): Composition {
val composition = setContent(content = content)

val observer = object : DefaultLifecycleObserver {
override fun onDestroy(owner: LifecycleOwner) {
owner.lifecycle.removeObserver(this)
composition.dispose()
}
}
lifecycle.lifecycle.addObserver(observer)

return composition
}
@@ -19,18 +19,17 @@ package app.tivi.episodedetails
import android.view.ViewGroup
import androidx.annotation.DrawableRes
import androidx.compose.Composable
import androidx.compose.Composition
import androidx.compose.ambient
import androidx.compose.state
import androidx.core.view.WindowInsetsCompat
import androidx.interpolator.view.animation.FastOutLinearInInterpolator
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.ui.core.DrawModifier
import androidx.ui.core.Modifier
import androidx.ui.core.OnChildPositioned
import androidx.ui.core.Text
import androidx.ui.core.WithDensity
import androidx.ui.core.setContent
import androidx.ui.foundation.Clickable
import androidx.ui.foundation.VerticalScroller
import androidx.ui.foundation.background
@@ -84,6 +83,7 @@ import app.tivi.common.compose.WrapInAmbients
import app.tivi.common.compose.center
import app.tivi.common.compose.observe
import app.tivi.common.compose.observeInsets
import app.tivi.common.compose.setContentWithLifecycle
import app.tivi.data.entities.Episode
import app.tivi.data.entities.EpisodeWatchEntry
import app.tivi.data.entities.PendingAction
@@ -101,11 +101,12 @@ import kotlin.math.hypot
* on Compose
*/
fun ViewGroup.composeEpisodeDetails(
lifecycleOwner: LifecycleOwner,
state: LiveData<EpisodeDetailsViewState>,
insets: LiveData<WindowInsetsCompat>,
actioner: (EpisodeDetailsAction) -> Unit,
tiviDateFormatter: TiviDateFormatter
): Any = setContent {
): Any = setContentWithLifecycle(lifecycleOwner) {
WrapInAmbients(tiviDateFormatter, InsetsHolder()) {
observeInsets(insets)

@@ -118,14 +119,6 @@ fun ViewGroup.composeEpisodeDetails(
}
}

/**
* We need to return an `Any` since this method will be called from modules which do not depend
* on Compose
*/
fun disposeComposition(composition: Any) {
(composition as? Composition)?.dispose()
}

@Composable
private fun EpisodeDetails(
viewState: EpisodeDetailsViewState,
@@ -45,10 +45,6 @@ class EpisodeDetailsFragment : TiviFragment(), EpisodeDetailsViewModel.FactoryPr
@Inject internal lateinit var episodeDetailsViewModelFactory: EpisodeDetailsViewModel.Factory
@Inject internal lateinit var textCreator: EpisodeDetailsTextCreator

// This should be the Composition type from Compose, but we unfortunately can't
// depend on Compose in this module (due to Coroutines)
private var currentComposition: Any? = null

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -57,7 +53,8 @@ class EpisodeDetailsFragment : TiviFragment(), EpisodeDetailsViewModel.FactoryPr
return FrameLayout(requireContext()).apply {
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)

currentComposition = composeEpisodeDetails(
composeEpisodeDetails(
viewLifecycleOwner,
viewModel.observeAsLiveData(),
observeWindowInsets(),
viewModel::submitAction,
@@ -66,13 +63,6 @@ class EpisodeDetailsFragment : TiviFragment(), EpisodeDetailsViewModel.FactoryPr
}
}

override fun onDestroyView() {
super.onDestroyView()

currentComposition?.let { disposeComposition(it) }
currentComposition = null
}

override fun invalidate() = Unit

override fun provideFactory(): EpisodeDetailsViewModel.Factory = episodeDetailsViewModelFactory

0 comments on commit 25ff426

Please sign in to comment.
You can’t perform that action at this time.