3

I have a module:

single{ (name: String) -> Person(name) }

When I do:

val alice: Person by inject {parametersOf("Alice")}
val bob: Person by inject {parametersOf("Bob")}

I get 2 instances of Alice. All parameters other than the first are ignored.

Is there a simple way to make Koin treat those 2 as different? Parameters are not known in advance, so I can't use named properties. factory won't do either, I need to reuse instances with same parameter sets.

Agent_L
  • 4,960
  • 28
  • 30

2 Answers2

6

There is no such thing directly in Koin, but it's easy enough to make something that works this way.

1) a class that does create-if-not-present:

class DistinctFactory<K, V>(private val newInstance: (K) -> V) {
    private val _locker = Any()
    private val mRepo: HashMap<K, V> = HashMap()

    operator fun get(id: K): V {
        return mRepo[id] ?: run {
            synchronized(_locker) {
                mRepo[id] ?: run {
                    newInstance(id).also {
                        mRepo[id] = it
                    }
                }
            }
        }
    }
}

2) Koin single of DistinctFactory:

single { DistinctFactory<String, Person> { Person(it) } }

3) Koin factory that uses the previous single:

factory { (name: String) -> get<DistinctFactory<String, Person>>()[name] }

test:

val alice: Person by inject {parametersOf("Alice")}
val bob: Person by inject {parametersOf("Bob")}
val aliceAgain: Person by inject {parametersOf("Alice")}

alice === aliceAgain
Agent_L
  • 4,960
  • 28
  • 30
0
module {

    val personCache = HashMap<Int, Person>()

    factory { parameters ->
        val hash = parameters.values.hashCode()
        personCache.getOrPut(hash) {
            Person(parameters.get())
        }
    }
}
  • This will only work sometimes because 1) hash is meant to not be unique. 2)`getOrPut` is not atomic so you're risking duplicates. – Agent_L Jun 29 '22 at 08:22