diff --git a/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/ActivityDerivedView.kt b/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/ActivityDerivedView.kt index 8e0ad6b..b4f814f 100644 --- a/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/ActivityDerivedView.kt +++ b/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/ActivityDerivedView.kt @@ -10,14 +10,22 @@ import kotlin.reflect.KProperty * Returns a property delegate for accessing [JetView] which is derived from the current activity (i.e. sharing * its [JetState] and [JetViewModel]). * - * Example: + * Derived view reference is released **before** `onDestroy()`, and accessing it after that will throw + * [IllegalStateException]. + * + * **Example of usage:** * ``` * class SomeView( * val viewBinding: MyLayoutBinding, * val viewModel: MyJetViewModel * ) : JetView { ... } - * ... - * val someView by derivedView { SomeView(viewBinding, viewModel) } + * + * class MyActivity : AppCompatActivity(), JetView { + * val someView by derivedView { SomeView(viewBinding!!, viewModel) } + * lateinit var viewBinding: MyLayoutBinding + * val viewModel: MyJetViewModel by jetViewModels(MyActivity::someView) + * ... + * } * ``` * * @param derivedViewProducer function returning derived view. It has parent view as its receiver. diff --git a/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/ActivityJetViewModelLazy.kt b/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/ActivityJetViewModelLazy.kt index d00cdb9..01db151 100644 --- a/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/ActivityJetViewModelLazy.kt +++ b/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/ActivityJetViewModelLazy.kt @@ -11,9 +11,9 @@ import androidx.lifecycle.viewmodel.CreationExtras * It uses Jetpack [viewModels] delegate under the hood. * * If you have [derived views][derivedView] in your activity which should be bound to the activity's [JetViewModel], - * you can [bind][bindDerived] them by passing them to this delegate function. + * you can [bind][bindDerived] them by passing references to them to this delegate function. * - * Example: + * **Example of usage:** * ``` * val derivedView1 by derivedView { DerivedView1(viewBinding, viewModel) } * val derivedView2 by derivedView { DerivedView2(viewBinding, viewModel) } @@ -25,7 +25,7 @@ import androidx.lifecycle.viewmodel.CreationExtras * ``` * * @param derivedViewProducer function which returns view derived from this activity. Derived view will be bound to the - * created JetViewModel. Derived views are created with [derivedView] delegate. + * returned JetViewModel. Derived views are created with [derivedView] delegate. * @see [viewModels] */ public inline fun V.jetViewModels( diff --git a/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/BindActivityJetView.kt b/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/BindActivityJetView.kt index 5bbeab4..86d03ef 100644 --- a/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/BindActivityJetView.kt +++ b/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/BindActivityJetView.kt @@ -7,11 +7,11 @@ import kotlinx.coroutines.flow.Flow /** * Launches lifecycle-aware collection of the [Flow] of [JetState] which will re-render view each time new state is - * emitted. + * emitted. It also accounts for [JetView.trackedState]. * * Binding by using [jetViewModels] delegate is preferred to manually calling this function, because it correctly * manages binding lifecycle. - * @param jetView a [JetView] to bind UI state flow to, parent [JetView] for [derivedViews]. + * @param jetView a view to bind UI state flow to, parent [JetView] for [derivedViews]. * @param derivedViews views derived from [jetView]. Created with [derivedView] delegate. * @return [Job] of the flow collection. */ @@ -23,7 +23,7 @@ public fun Flow.bind(jetView: V, vararg derivedViews: JetVi /** * Launches lifecycle-aware collection of the [Flow] of [JetState] which will re-render _only_ derived views each time - * new state is emitted. + * new state is emitted. It also accounts for [JetView.trackedState]. * * Binding by using [jetViewModels] delegate is preferred to manually calling this function, because it correctly * manages binding lifecycle. diff --git a/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/BindFragmentJetView.kt b/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/BindFragmentJetView.kt index 6c09dd9..e83814c 100644 --- a/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/BindFragmentJetView.kt +++ b/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/BindFragmentJetView.kt @@ -8,13 +8,13 @@ import kotlinx.coroutines.flow.Flow /** * Launches lifecycle-aware collection of the [Flow] of [JetState] which will re-render [jetView] each time new state is - * emitted. + * emitted. It also accounts for [JetView.trackedState]. * * Binding by using [jetViewModels] delegate is preferred to manually calling this function, because it automatically * determines necessary [Lifecycle] to launch coroutines with and correctly manages binding lifecycle. * * **Do not use in non-UI fragments, as it assumes that fragment's view is not null. Use [bindHeadless] instead.** - * @param jetView a [JetView] to bind UI state flow to, parent [JetView] for [derivedViews]. + * @param jetView a view to bind UI state flow to, parent [JetView] for [derivedViews]. * @param derivedViews views derived from [jetView]. Created with [derivedView] delegate. * @return [Job] of the flow collection. */ @@ -31,7 +31,7 @@ public fun Flow.bind(jetView: V, vararg derivedViews: JetVi /** * Launches lifecycle-aware collection of the [Flow] of [JetState] which will re-render _only_ derived views each time - * new state is emitted. + * new state is emitted. It also accounts for [JetView.trackedState]. * * Binding by using [jetViewModels] delegate is preferred to manually calling this function, because it automatically * determines necessary [Lifecycle] to launch coroutines with and correctly manages binding lifecycle. @@ -56,14 +56,14 @@ public fun Flow.bindDerived(parentView: V, vararg derivedVi /** * Launches lifecycle-aware collection of the [Flow] of [JetState] for non-UI fragment which will re-render it each time - * new state is emitted. + * new state is emitted. It also accounts for [JetView.trackedState]. * * Binding by using [jetViewModels] delegate is preferred to manually calling this function, because it automatically * determines necessary [Lifecycle] to launch coroutines with and correctly manages binding lifecycle. * * **Use only in non-UI fragments, as it doesn't respect fragment's view lifecycle. Use [bind] for fragments with a * view.** - * @param jetView a [JetView] to bind UI state flow to. + * @param jetView a view to bind UI state flow to. * @return [Job] of the flow collection. */ public fun Flow.bindHeadless(jetView: V, vararg derivedViews: JetView): Job @@ -74,7 +74,7 @@ public fun Flow.bindHeadless(jetView: V, vararg derivedView /** * Launches lifecycle-aware collection of the [Flow] of [JetState] for non-UI fragment which will re-render _only_ - * derived views each time new state is emitted. + * derived views each time new state is emitted. It also accounts for [JetView.trackedState]. * * Binding by using [jetViewModels] delegate is preferred to manually calling this function, because it automatically * determines necessary [Lifecycle] to launch coroutines with and correctly manages binding lifecycle. diff --git a/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/FragmentDerivedView.kt b/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/FragmentDerivedView.kt index 9486605..75b7694 100644 --- a/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/FragmentDerivedView.kt +++ b/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/FragmentDerivedView.kt @@ -11,14 +11,29 @@ import kotlin.reflect.KProperty * Returns a property delegate for accessing [JetView] which is derived from the current fragment (i.e. sharing * its [JetState] and [JetViewModel]). * - * Example: + * Derived view reference is released **before** `onDestroy()`, and accessing it after that will throw + * [IllegalStateException]. + * + * **For fragment with a view:** + * + * In fragment with a view, derived view reference will be released when fragment's view is destroyed, and derived view + * will be recreated on first access after that (if using [jetViewModels] or [activityJetViewModels] delegate, it + * happens automatically when fragment's view is recreated). When accessing derived view after `onDestroyView()` and + * before `onCreateView()` returns, this delegate will throw [IllegalStateException]. + * + * **Example of usage:** * ``` * class SomeView( * val viewBinding: MyLayoutBinding, * val viewModel: MyJetViewModel * ) : JetView { ... } - * ... - * val someView by derivedView { SomeView(viewBinding, viewModel) } + * + * class MyFragment : Fragment(), JetView { + * val someView by derivedView { SomeView(viewBinding!!, viewModel) } + * var viewBinding: MyLayoutBinding? = null + * val viewModel: MyJetViewModel by jetViewModels(MyFragment::someView) + * ... + * } * ``` * * @param derivedViewProducer function returning derived view. It has parent view as its receiver. diff --git a/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/FragmentJetViewModelLazy.kt b/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/FragmentJetViewModelLazy.kt index 468616a..dc7faf2 100644 --- a/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/FragmentJetViewModelLazy.kt +++ b/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/FragmentJetViewModelLazy.kt @@ -12,9 +12,17 @@ import androidx.lifecycle.viewmodel.CreationExtras * It uses Jetpack [viewModels] delegate under the hood. * * If you have [derived views][derivedView] in your fragment which should be bound to the fragment's [JetViewModel], - * you can [bind][bindDerived] them by passing them to this delegate function. + * you can [bind][bindDerived] them by passing references to them to this delegate function. * - * Example: + * **For fragment with a view:** + * + * If fragment has a view, binding happens after fragment's view is created using fragment's view lifecycle. + * + * **For fragment without a view:** + * + * If fragment doesn't have a view, binding happens after fragment's first `onStart()` using fragment's lifecycle. + * + * **Example of usage:** * ``` * val derivedView1 by derivedView { DerivedView1(viewBinding, viewModel) } * val derivedView2 by derivedView { DerivedView2(viewBinding, viewModel) } @@ -26,7 +34,7 @@ import androidx.lifecycle.viewmodel.CreationExtras * ``` * * @param derivedViewProducer function which returns view derived from this fragment. Derived view will be bound to the - * created JetViewModel. Derived views are created with [derivedView] delegate. + * returned JetViewModel. Derived views are created with [derivedView] delegate. * @see [viewModels] */ public inline fun V.jetViewModels( @@ -49,9 +57,17 @@ public inline fun V.jetViewModels( * It uses Jetpack [activityViewModels] delegate under the hood. * * If you have [derived views][derivedView] in your fragment which should be bound to the fragment's [JetViewModel], - * you can [bind][bindDerived] them by passing them to this delegate function. + * you can [bind][bindDerived] them by passing references to them to this delegate function. + * + * **For fragment with a view:** + * + * If fragment has a view, binding happens after fragment's view is created using fragment's view lifecycle. + * + * **For fragment without a view:** + * + * If fragment doesn't have a view, binding happens after fragment's first `onStart()` using fragment's lifecycle. * - * Example: + * **Example of usage:** * ``` * val derivedView1 by derivedView { DerivedView1(viewBinding, viewModel) } * val derivedView2 by derivedView { DerivedView2(viewBinding, viewModel) } diff --git a/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/JetView.kt b/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/JetView.kt index 8b38412..48ddf8d 100644 --- a/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/JetView.kt +++ b/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/JetView.kt @@ -8,9 +8,9 @@ public interface JetView { /** * Properties of [JetState] whose changes are tracked by this view. When this list is empty (it is by default), * [render] method will be called on every UI state update. Override this to skip render when unrelated properties - * change (may be useful in [derived views][derivedView]). + * change (may be useful with [derived views][derivedView]). * - * Example: + * **Example of usage:** * ``` * override val trackedState = listOf(MyUiState::isButtonEnabled, MyUiState::buttonText) * ``` diff --git a/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/JetViewModel.kt b/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/JetViewModel.kt index 244c426..b7bc23d 100644 --- a/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/JetViewModel.kt +++ b/jetmvi/src/main/kotlin/io/github/solrudev/jetmvi/JetViewModel.kt @@ -8,7 +8,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update /** - * Only instances of this sealed interface can be obtained from [jetViewModels] delegate. + * Only instances of this sealed interface can be obtained from [jetViewModels] and [activityJetViewModels] delegates. * * Implemented by [FeatureViewModel] and [UDFViewModel]. */