Search code examples
androiddagger-2

Dagger 2 dynamic injection when button gets clicked


Not sure if it is possible or not. However, I am looking for a way to solve this.

class User(val name: String, val email: String)

class MyActivity : AppCompatActivity {
    @Inject lateinit var vm: MyViewModel

    override fun onCreate(bundle: Bundle?) {
        DaggerMyActivityComponent.create().inject(this)
        super.onCreate(bundle)
        setContentView(R.layout.activity_my)

        myButton.setOnClickListener {
            vm.insert(pathEditText.text.toString(), User("test name", "test email"))
        }
    }
}

class MyViewModel @Inject constructor(val repo: MyRepository) {
    fun insert(path: String, user: User) {
        repo.insert(user)
    }
}

class MyRepository(path: String) {
    val collection = Firebase.firestore.collection(path)

    fun insert(user: User) {
        collection.set(user)
    }
}

@Component(modules = [MyModule::class])
interface MyActivityComponent {
    fun inject(activity: MyActivity)
}

@Module class MyModule {
    @Provides fun repo() = MyRepository(How do I get the path here?)
}

Question:

How do I get the path being injected into MyModule's @Provides fun repo() dynamically since the path can only be known when user types the EditText.

I am not sure if it is possible or not. However, would love to know a possible solution. I am even ready to change my overall solution if it fits my situation.


Solution

  • You can use a flyweight factory to create new repo instances. Like this:

    class MyRepositoryFactory {
    
      fun create(path: String): MyRepository {
        return MyRepository(path)
      }
    
    }
    
    @Module class MyModule {
        @Provides fun repoFactory() = MyRepositoryFactory()
    }
    
    class MyViewModel @Inject constructor(val repoFactory: MyRepositoryFactory) {
        fun insert(path: String, user: User) {
            repoFactory.create(path).insert(user)
        }
    }