bluelinelabs / Conductor

A small, yet full-featured framework that allows building View-based Android applications
Apache License 2.0
3.89k stars 342 forks source link

Way to scope dagger subcomponents via backstack #619

Open ursusursus opened 4 years ago

ursusursus commented 4 years ago

Hi, this is a uninformed question, but, often times I hear that "screen" frameworks provide a mechanism of creating and storing a subcomponent instance, and then clearing it on popping

Anybody tried something like this with Conductor?

PaulWoitaschek commented 4 years ago

I have an AddFoodController. That controller has it's own component:

@Qualifier
annotation class AddFoodLifecycle

@Subcomponent(modules = [FoodBottomBarListenerModule::class])
@AddFoodScope
interface AddFoodComponent : JustAddedComponent {

  val foodSearchComponentFactory: FoodSearchController.Component.Factory

  fun inject(target: AddFoodController)

  @Subcomponent.Factory
  interface Factory {
    fun create(
      @BindsInstance args: AddFoodArgs,
      @BindsInstance @AddFoodLifecycle lifecycle: Lifecycle
    ): AddFoodComponent
  }

  companion object {
    lateinit var factory: Factory
  }
}

This controller creates the component in its init block:


  private val component: AddFoodComponent
  init {
    component = AddFoodComponent.factory.create(args, lifecycle)
    component.inject(this)
  }

I have an FoodSearchController.

For that controller I have an interface for creating the component factory:

interface FoodSearchComponentProvider {
  val foodSearchComponentFactory: FoodSearchController.Component.Factory
}

That interface is implemented by the AddFoodController.

Now the FoodSearchController uses onContextAvailable to inject it's dependencies:

  override fun onContextAvailable(context: Context) {
    super.onContextAvailable(context)
    if (!dependenciesInjected) {
      (targetController as FoodSearchComponentProvider).foodSearchComponentFactory.create(lifecycle).inject(this)
    }
    dependenciesInjected = true
  }

That way they can share the same scoped instances. Would that work for you?

ursusursus commented 4 years ago

In a sense it would, youre holding the instance in one, and sharing the reference via targetController api, and when the host gets popped the component is lost.

I was thinking more of something like a purchase flow. Where none of the controllers in the logical flow instantiate the component, they just access it from "somewhere". And the instantiation would happen "automatically" else where.

I was thinking putting it in the backstackchanged listener, manually like if controller pushed is PurchaseFirstStepController then create the instance, if popped then clear it

Mortar has a way to attach stuff to backstack entry objects