Last active
May 20, 2021 15:01
-
-
Save bmc08gt/2a6076588401a07fda709df06485c295 to your computer and use it in GitHub Desktop.
DIY DI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| interface AppComponent : Component { | |
| val appContext: Context | |
| } | |
| class AppConfig( | |
| override val appContext: Context, | |
| ) : AppComponent |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import androidx.annotation.MainThread | |
| interface Component | |
| @MainThread | |
| inline fun <reified C : Component> components(): Lazy<C> { | |
| return ComponentLazy(C::class) | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // jetpack startup initializer to not add this to App subclass | |
| class ComponentInitializer : Initializer<Unit> { | |
| override fun create(context: Context) { | |
| ComponentRouter.init(context) { | |
| inject(FeatureConfig(app.appContext)) | |
| } | |
| } | |
| override fun dependencies(): List<Class<out Initializer<*>>> { | |
| return emptyList() | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import kotlin.reflect.KClass | |
| import kotlin.reflect.KProperty0 | |
| class ComponentLazy<C : Component> ( | |
| private val componentClass: KClass<C> | |
| ) : Lazy<C> { | |
| private var cached: C? = null | |
| override val value: C | |
| get() { | |
| val component = cached | |
| return if (component == null) { | |
| val match = ComponentRouter.getComponent<C>(componentClass.java) | |
| requireNotNull(match) { | |
| ComponentNotRegisteredException(componentClass::simpleName) | |
| } | |
| return match.also { cached = it } | |
| } else { | |
| component | |
| } | |
| } | |
| override fun isInitialized() = cached != null | |
| } | |
| class ComponentNotRegisteredException(name: KProperty0<String?>) : RuntimeException("${name.get()} not registered") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| object ComponentRouter { | |
| private const val TAG = "ComponentRouter" | |
| val DEBUG = false | |
| val components: MutableMap<Class<out Component>, Component> = mutableMapOf() | |
| fun <T: Component> getComponent(clazz: Class<out Component>): T? { | |
| fun checkInterfaces(klass: Class<Component>): Boolean { | |
| if (klass.interfaces.isEmpty()) return false | |
| log("klazz name=${klass.interfaces.first().canonicalName}") | |
| return klass.interfaces.first().canonicalName == clazz.canonicalName | |
| } | |
| fun iterateInterfaces(klass: Class<Component>): Boolean { | |
| if (klass.canonicalName == clazz.canonicalName) return true | |
| val match = checkInterfaces(klass) | |
| if (match) { | |
| return match | |
| } | |
| return klass.interfaces.any { k -> iterateInterfaces(k as Class<Component>) } | |
| } | |
| val match = components.values.find { iterateInterfaces(it.javaClass) } | |
| return match as? T | |
| } | |
| fun init(appContext: Context, block: (Initializer.() -> Unit)? = null): ComponentRouter { | |
| Initializer().apply { | |
| with(AppConfig(appContext)) { | |
| inject(this) | |
| appComponent = this | |
| } | |
| block?.invoke(this) | |
| } | |
| return this | |
| } | |
| private fun log(message: String) { | |
| if (DEBUG) { | |
| Log.d(TAG, message) | |
| } | |
| } | |
| class Initializer { | |
| lateinit var appComponent: AppComponent | |
| fun inject(component: Component) { | |
| with(component) { | |
| components[this::class.java] = component | |
| } | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| interface FeatureComponent : Component { | |
| val db: RoomDatabase | |
| } | |
| class FeatureConfig( | |
| context: Context, | |
| ) : FeatureComponent { | |
| override val db: RoomData = // construct your db | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| FeatureComponent component = ComponentRouter.INSTANCE.getComponent(FeatureComponent.class); | |
| if (component != null) { | |
| component.getDb(); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| val feature by components<FeatureComponent>() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment