Skip to content

Commit

Permalink
Move main thread scheduler to FragmentFlowStore.
Browse files Browse the repository at this point in the history
  • Loading branch information
Laimiux committed Jan 26, 2024
1 parent 25f6b12 commit 2cc53c3
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.instacart.formula.Formula
import com.instacart.formula.Snapshot
import com.instacart.formula.android.internal.Binding
import com.instacart.formula.android.events.FragmentLifecycleEvent
import com.instacart.formula.android.internal.FeatureObservableAction
import com.instacart.formula.rxjava3.RxAction
import com.instacart.formula.rxjava3.toObservable
import com.jakewharton.rxrelay3.PublishRelay
Expand Down Expand Up @@ -122,14 +123,18 @@ class FragmentFlowStore @PublishedApi internal constructor(
val fragmentId = entry.key
val feature = (entry.value as? FeatureEvent.Init)?.feature
if (feature != null) {
RxAction.fromObservable(feature) {
feature.state.onErrorResumeNext {
input.onScreenError(fragmentId.key, it)
Observable.empty()
val action = FeatureObservableAction(
fragmentEnvironment = input,
fragmentId = fragmentId,
feature = feature,
)
action.onEvent {
if (state.activeIds.contains(fragmentId)) {
val keyState = FragmentState(fragmentId.key, it)
transition(state.copy(states = state.states.plus(fragmentId to keyState)))
} else {
none()
}
}.onEvent {
val keyState = FragmentState(fragmentId.key, it)
transition(state.copy(states = state.states.plus(fragmentId to keyState)))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import com.instacart.formula.android.events.ActivityResult
import com.instacart.formula.android.FragmentEnvironment
import com.instacart.formula.android.ActivityStore
import com.instacart.formula.android.FormulaFragment
import com.instacart.formula.android.FragmentFlowState
import com.instacart.formula.android.ViewFactory
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.disposables.Disposable
Expand All @@ -20,24 +19,18 @@ internal class ActivityManager<Activity : FragmentActivity>(
private val store: ActivityStore<Activity>
) {

private val fragmentState = store
.contracts
.state(environment)
.doOnNext(delegate.fragmentFlowStateRelay::accept)
.replay(1)

internal val stateSubscription: Disposable
private var uiSubscription: Disposable? = null
private var fragmentRenderView: FragmentFlowRenderView? = null

init {
stateSubscription = if (store.streams != null) {
val disposables = CompositeDisposable()
disposables.add(fragmentState.connect())
disposables.add(subscribeToFragmentStateChanges())
disposables.add(store.streams.invoke(StreamConfiguratorIml(delegate)))
disposables
} else {
fragmentState.connect()
subscribeToFragmentStateChanges()
}
}

Expand All @@ -63,12 +56,10 @@ internal class ActivityManager<Activity : FragmentActivity>(
delegate.onLifecycleStateChanged(Lifecycle.State.CREATED)
val renderView = fragmentRenderView ?: throw callOnPreCreateException(activity)

val updateScheduler = AndroidUpdateScheduler<FragmentFlowState> {
uiSubscription = delegate.fragmentFlowState().subscribe {
renderView.render(it)
store.onRenderFragmentState?.invoke(activity, it)
}

uiSubscription = fragmentState.subscribe(updateScheduler::emitUpdate)
}

fun onActivityStarted(activity: Activity) {
Expand Down Expand Up @@ -115,6 +106,13 @@ internal class ActivityManager<Activity : FragmentActivity>(
return fragmentRenderView?.viewFactory(fragment)
}

private fun subscribeToFragmentStateChanges(): Disposable {
return store
.contracts
.state(environment)
.subscribe(delegate.fragmentFlowStateRelay::accept)
}

private fun callOnPreCreateException(activity: FragmentActivity): IllegalStateException {
return IllegalStateException("please call onPreCreate before calling Activity.super.onCreate(): ${activity::class.java.simpleName}")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ internal class FeatureBinding<in Component, in Dependencies, in Key : FragmentKe
if (binds(key)) {
Action.onData(fragmentId).onEvent {
transition {
// TODO: should this happen on the main thread? It needs to be available to main thread
try {
val dependencies = toDependencies(input.component)
val feature = input.environment.fragmentDelegate.initializeFeature(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.instacart.formula.android.internal

import com.instacart.formula.Action
import com.instacart.formula.Cancelable
import com.instacart.formula.android.Feature
import com.instacart.formula.android.FragmentEnvironment
import com.instacart.formula.android.FragmentId
import io.reactivex.rxjava3.core.Observable

class FeatureObservableAction(
private val fragmentEnvironment: FragmentEnvironment,
private val fragmentId: FragmentId,
private val feature: Feature<*>,
) : Action<Any> {

override fun key(): Any = fragmentId

override fun start(send: (Any) -> Unit): Cancelable {
val observable = feature.state.onErrorResumeNext {
fragmentEnvironment.onScreenError(fragmentId.key, it)
Observable.empty()
}

// We ensure all feature state updates come on the main thread.
val androidUpdateScheduler = AndroidUpdateScheduler(send)
val disposable = observable.subscribe(androidUpdateScheduler::emitUpdate)
return Cancelable(disposable::dispose)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ internal class FragmentFlowRenderView(

private val featureProvider = object : FeatureProvider {
override fun getFeature(id: FragmentId): FeatureEvent? {
// TODO: should we initialize feature if it's missing
return fragmentState?.features?.get(id)
}
}
Expand Down

0 comments on commit 2cc53c3

Please sign in to comment.