Skip to content

Commit 563974b

Browse files
committed
Update README.md
1 parent 93352e9 commit 563974b

File tree

1 file changed

+190
-11
lines changed

1 file changed

+190
-11
lines changed

README.md

+190-11
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,208 @@ DependencyProperty
33

44
`DependencyProperty` is a dependency resolution library by Delegated Property.
55

6+
## Overview
7+
8+
`DependencyProperty` is
9+
10+
- simple in defining and resolving dependencies.
11+
- usable in classes accessible to Application instance like Activity, Fragment, and etc.
12+
- able to constructor injection to ViewModel without affecting other classes.
13+
- less code for testing than Dagger Hilt.
14+
- easy to use in multi-module and Dynamic Feature Module.
15+
- easy to manage modules lifecycle.
16+
- faster build time than Dagger.
17+
- faster execution time than Dagger and Koin.
18+
619
## Usage
7-
### Application
20+
### Configure DependencyProperty in Application
21+
Application class must implements `DependencyModulesHolder` like below.
22+
23+
```kt
24+
class App: Application(), DependencyModulesHolder {
25+
override val dependencyModules: DependencyModules by dependencyModules(AppModule(this), CoroutinesModule())
26+
}
27+
```
28+
29+
You can pass variable number of arguments(`DependencyModule`) to `dependencyModules()`.
30+
31+
### Define dependencies in DependencyModule
32+
`DependencyModule` is marker interface.
33+
You can define dependencies as property and function.
34+
35+
```kt
36+
open class CoroutinesModule : DependencyModule {
37+
open val defaultDispatcher: CoroutineDispatcher = Dispatchers.Default
38+
open val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
39+
open val mainDispatcher: CoroutineDispatcher = Dispatchers.Main
40+
open val mainImmediateDispatcher: CoroutineDispatcher = Dispatchers.Main.immediate
41+
}
42+
```
43+
44+
You can resolve other DependencyModule using below extension methods.
45+
46+
- `inline fun <reified T : DependencyModule> Application.dependencyModule(): T`
47+
- `inline fun <reified T : DependencyModule> FragmentActivity.dependencyModule(): T`
48+
- `inline fun <reified T : DependencyModule> Fragment.dependencyModule(): T`
49+
- `inline fun <reified T : DependencyModule> AndroidViewModel.dependencyModule(): T`
50+
- `inline fun <reified T : DependencyModule> Service.dependencyModule(): T`
51+
52+
```kt
53+
class AppModule(private val application: Application) : DependencyModule {
54+
private val coroutinesModule: CoroutinesModule by lazy {
55+
application.dependencyModule<CoroutinesModule>()
56+
}
57+
val loadItemsUseCase: LoadItemsUseCase
58+
get() = LoadItemsUseCase(coroutineModule.ioDispatcher)
59+
}
60+
```
61+
62+
- If You want to define dependency as singleton, you can define property as lazy.
63+
- If You want to define dependency as not singleton, you can define property as getter.
64+
- If You want to define dependency using parameters, you can define property as function.
65+
66+
### Resolve dependencies
67+
68+
You can resolve dependency by delegated property using below extension methods.
69+
70+
- `fun <T: DependencyModule, R> Application.dependency<T, R>(resolve: (T) -> R): Lazy<R>`
71+
- `fun <T: DependencyModule, R> FragmentActivity.dependency<T, R>(resolve: (T) -> R): Lazy<R>`
72+
- `fun <T: DependencyModule, R> Fragment.dependency<T, R>(resolve: (T) -> R): Lazy<R>`
73+
- `fun <T: DependencyModule, R> AndroidViewModel.dependency<T, R>(resolve: (T) -> R): Lazy<R>`
74+
- `fun <T: DependencyModule, R> Service.dependency<T, R>(resolve: (T) -> R): Lazy<R>`
75+
76+
Activity's example is below.
77+
78+
```kt
79+
class MainActivity : AppCompatActivity() {
80+
private val loadItemsUseCase by dependency<AppModule, LoadItemsUseCase> { it.loadItemsUseCase }
81+
}
82+
```
83+
84+
For testing, ViewModel inherits AndroidViewModel and its constructor is annotated `@JvmOverloads`.
85+
86+
```kt
87+
class MainViewModel @JvmOverloads constructor(
88+
application: Application,
89+
savedStateHandle: SavedStateHandle
90+
private val loadItemsUseCase: LoadItemsUseCase = application.dependencyModule<AppModule>().loadItemsUseCase
91+
) : AndroidViewModel(application) {
92+
// You can use loadItemsUseCase
93+
}
94+
```
95+
96+
By @JvmOverloads, ViewModel's dependencies is passed as default arguments.
97+
98+
### Unit Test
99+
100+
In Unit Test, DependencyProperty is not used.
101+
You can inject to constructor.
102+
103+
```kt
104+
@Test
105+
fun test() {
106+
// init loadItemsUseCase
107+
// ...
108+
// init ViewModel
109+
val viewModel = MainViewModel(Application(), SavedStateHandle(), loadItemsUseCase)
110+
// test ViewModel
111+
}
112+
```
113+
114+
### UI Test
115+
116+
You need only to define CustomTestRunner and Application for testing.
117+
118+
```gradle
119+
android {
120+
defaultConfig {
121+
// Replace com.example with your class path.
122+
testInstrumentationRunner "com.example.CustomTestRunner"
123+
}
124+
}
125+
```
126+
127+
```kt
128+
class CustomTestRunner : AndroidJUnitRunner() {
129+
override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application {
130+
return super.newApplication(cl, TestApp::class.java.name, context)
131+
}
132+
}
133+
```
134+
135+
You can override DependencyModule by passing inherited DependencyModule.
136+
137+
```kt
138+
class TestApp: Application(), DependencyModulesHolder {
139+
override val dependencyModules: DependencyModules by dependencyModules(AppModule(this), TestCoroutinesModule())
140+
}
141+
```
142+
143+
TestCoroutinesModule inherits CoroutinesModule and overrides its properties.
144+
145+
```kt
146+
class TestCoroutinesModule : CoroutinesModule() {
147+
override val defaultDispatcher: CoroutineDispatcher = AsyncTask.THREAD_POOL_EXECUTOR.asCoroutineDispatcher()
148+
override val ioDispatcher: CoroutineDispatcher = AsyncTask.THREAD_POOL_EXECUTOR.asCoroutineDispatcher()
149+
override val mainDispatcher: CoroutineDispatcher = Dispatchers.Main
150+
override val mainImmediateDispatcher: CoroutineDispatcher = Dispatchers.Main.immediate
151+
}
152+
```
153+
154+
### Multi-module and Dynamic Feature Module
155+
156+
In multi-module, no extra settings.
157+
You can use other module's DependencyModule in app module.
158+
8159
```kt
9160
class App: Application(), DependencyModulesHolder {
10-
override val dependencyModules: DependencyModules by dependencyModules(AppModule())
161+
override val dependencyModules: DependencyModules by dependencyModules(AppModule(this), CoroutinesModule())
11162
}
12163
```
13164

14-
### Module
165+
In Dynamic Feature Module, you can add DependencyModule dynamically using below extension methods.
166+
167+
```kt
168+
val Application.dependencyModules: DependencyModules
169+
get() = (this as DependencyModulesHolder).dependencyModules
170+
val FragmentActivity.dependencyModules: DependencyModules
171+
get() = application.dependencyModules
172+
val Fragment.dependencyModules: DependencyModules
173+
get() = requireActivity().application.dependencyModules
174+
val AndroidViewModel.dependencyModules: DependencyModules
175+
get() = getApplication<Application>().dependencyModules
176+
val Service.dependencyModules: DependencyModules
177+
get() = application.dependencyModules
178+
```
179+
180+
Activity's example is below.
181+
15182
```kt
16-
class AppModule : DependencyModule {
17-
val singleton: String by lazy { "singleton" }
18-
val factory: String get() = "factory"
19-
fun provide(instance: Int): Pair<String, Int> = singleton to instance
183+
class MainActivity : AppCompatActivity() {
184+
override fun onCreate(savedInstanceState: Bundle?) {
185+
super.onCreate(savedInstanceState)
186+
dependencyModules.addModule(DynamicModule()) // add only once
187+
}
20188
}
21189
```
22190

23-
### Activity/Fragment/AndroidViewModel
191+
### Lifecycle of DependencyModule
192+
193+
You can manage lifecycle of DependencyModule below methods.
194+
195+
- `fun <T: DependencyModule> DependencyModules.addModule(module: T)`
196+
- `fun <T: DependencyModule> DependencyModules.removeModule<T>()`
197+
- `fun <T: DependencyModule> DependencyModules.replaceModule(module: T)`
198+
199+
Activity's example is below.
200+
24201
```kt
25202
class MainActivity : AppCompatActivity() {
26-
private val singleton by dependency<AppModule, String> { it.singleton }
27-
private val factory by dependency<AppModule, String> { it.factory }
28-
private val provide by dependency<AppModule, Pair<String, Int>> { it.provide(42) }
203+
override fun onCreate(savedInstanceState: Bundle?) {
204+
super.onCreate(savedInstanceState)
205+
// Replace an existing DependencyModule of the same type with a new DependencyModule
206+
dependencyModules.replaceModule(AppModule(application))
207+
}
29208
}
30209
```
31210

0 commit comments

Comments
 (0)