๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿค์•ˆ๋“œ๋กœ์ด๋“œ ๊ฐœ๋ฐœ ๊ธฐ๋ก/Filmo ์˜ํ™” ํ”„๋กœ์ ํŠธ

[Android : Kotlin] ์˜์กด์„ฑ ์ฃผ์ž…์˜ ๊ธฐ๋ณธ์„ ์ดํ•ดํ•ด๋ณด์ž~!

by hyeonha 2024. 12. 27.

๋“ค์–ด๊ฐ€๊ธฐ ์ „์—

ํ”„๋กœ์ ํŠธ์—์„œ Hilt๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค. ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ธฐ์— ๋ฐ”๋น  Hilt๊ฐ€ ๋‚˜์˜ค๊ธฐ๊นŒ์ง€ ํ๋ฆ„์„ ์ œ๋Œ€๋กœ ์‹œ๊ฐ„ ๋“ค์—ฌ ๊ณต๋ถ€ํ•ด๋ณด์ง€ ๋ชปํ–ˆ๋Š”๋ฐ ์•ฑ ์ถœ์‹œ๋ฅผ ์œ„ํ•ด ํ…Œ์ŠคํŠธ๊นŒ์ง€ ๊ฑธ๋ฆฌ๋Š” ๊ธฐ๊ฐ„๋™์•ˆ ๊ทธ๋™์•ˆ ๋ชปํ–ˆ๋˜ ๊ณต๋ถ€๋ฅผ ํ•˜๋ฉฐ ๋ถ€์กฑํ•œ ๋‚ด์šฉ์„ ์ฑ„์›Œ๋ณด๋ คํ•œ๋‹ค~! ์˜ค๋Š˜์€ ์˜์กด์„ฑ ์ฃผ์ž…ํŒŒํŠธ!!

์•„์ž์ž

์˜์กด์„ฑ ์ฃผ์ž… ๊ธฐ๋ณธ

์•กํ‹ฐ๋น„ํ‹ฐ์—์„œ ๋ทฐ๋ชจ๋ธ ๊ฐ์ฒด๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ

๋ทฐ๋ชจ๋ธ ๊ฐ์ฒด๋ฅผ ๊ตฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋ ˆํฌ์ง€ํ† ๋ฆฌ ๊ฐ์ฒด๊ฐ€ ํ•„์š”
๋ ˆํฌ์ง€ํ† ๋ฆฌ ๊ฐ์ฒด๋ฅผ ๊ตฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ์ดํ„ฐ ์†Œ์Šค ๊ฐ์ฒด๊ฐ€ ํ•„์š”
๋ฐ์ดํ„ฐ ์†Œ์Šค ๊ฐ์ฒด๋ฅผ ๊ตฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด์„œ ์„œ๋น„์Šค ๊ฐ์ฒด๊ฐ€ ํ•„์š”
์„œ๋น„์Šค ๊ฐ์ฒด๋ฅผ ๊ตฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ ˆํŠธ๋กœํ• ๊ฐ์ฒด๊ฐ€ ํ•„์š”

// ์ฝ”๋“œ ๊ตฌํ˜„ ์‹œ
0. ๋ ˆํŠธ๋กœํ• ๊ฐ์ฒด ๊ตฌ์„ฑ
1. ์„œ๋น„์Šค ๊ฐ์ฒด ๊ตฌ์„ฑ
2. ๋ฐ์ดํ„ฐ ์†Œ์Šค ๊ฐ์ฒด ๊ตฌ์„ฑ 
3. ๋ ˆํฌ์ง€ํ† ๋ฆฌ ๊ฐ์ฒด ๊ตฌ์„ฑ
4. ๋ทฐ๋ชจ๋ธ ๊ฐ์ฒด ๊ตฌ์„ฑ

 

์œ„์™€ ๊ฐ™์ด ์ˆœ์„œ๋Œ€๋กœ ๊ตฌํ˜„ํ•ด์ค˜์•ผํ•œ๋‹ค.

๋‹ค๋ฅธ ๋ถ€๋ถ„์—์„œ ๋‹ค๋ฅธ ๋ทฐ๋ชจ๋ธ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“œ๋ ค๊ณ  ํ•œ๋‹ค๋ฉด ์œ„ ๊ณผ์ •์„ ์ค‘๋ณตํ•ด์„œ ๊ตฌํ˜„ํ•„์š”

์ข…์† ํ•ญ๋ชฉ์„ ์ˆœ์„œ๋Œ€๋กœ ์„ ์–ธํ•ด์ค˜์•ผํ•œ๋‹ค.

๊ฐ์ฒด๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์–ด๋ ต๋‹ค.

์ปจํ…Œ์ด๋„ˆ๋กœ ์ข…์† ํ•ญ๋ชฉ ๊ด€๋ฆฌ

  • ๊ฐ์ฒด ์žฌ์‚ฌ์šฉ ๋ฌธ์ œ ํ•ด๊ฒฐ์„ ์œ„ํ•ด
  • ์ข…์† ํ•ญ๋ชฉ์„ ๊ฐ€์ ธ์˜ค๋Š”๋ฐ ์‚ฌ์šฉํ•˜๋Š” ์ž์ฒด ์ข…์† ํ•ญ๋ชฉ ์ปจํ…Œ์ด๋„ˆ ํด๋ž˜์Šค ์ƒ์„ฑ!
  • Application์— ๋ฐฐ์น˜ํ•˜๊ธฐ
// Application.kt

class Application : Application() {

	// ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ๋”ฐ๋ฅด์ง€ ์•Š์Œ
	//  ์•ฑ ์ „์ฒด์—์„œ ๊ณต์œ ๋˜๋Š” ๊ณ ์œ ํ•œ ์ธ์Šคํ„ด์Šค๊ฐ€ ์žˆ๋Š” ํด๋ž˜์Šค์ด๋‹ค. 
	val appContainer : AppContainer() 
	
	}
  • AppContainer
class AppContainer {

 val userViewModelFactory = UserViewModelFactory(userRepository)
	
	 private val retrofit = Retrofit
            .Builder()
            .baseUrl(movieApiBaseUrl)
            .client(OkHttpClient)
            .addCallAdapterFactory(ResultCallAdapter.Factory(retryCount))
            .addConverterFactory(json.asConverterFactory(contentType.toMediaType()))
            .build()
            
            
    
  private val userService = retrofit.create(UserService::class.java)
   
   
  private val userDataSource = UserDataSourceImpl(userService)
	
	val userRepository = UserRepositoryImpl(userDataSource)
	

  • ํ”„๋ž˜๊ทธ๋จผํŠธ์—์„œ ๋ทฐ ๋ชจ๋ธ ๊ฐ์ฒด ๋งŒ๋“ค๊ธฐ
class UserFragment : Fragment() {
private lateinit var viewModel : UserViewModel

 override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Gets userRepository from the instance of AppContainer in Application
        
        val appContainer = (application as Application).appContainer
//        viewModel = UserViewModel(appContainer.userRepository)

viewModel = appContainer.userViewModelFactory.create()
    }
}

 

์ด๋ ‡๊ฒŒ ๋งŒ๋“ค์–ด์ง„ UserRepository ๊ฐ์ฒด๋Š” ์‹ฑ๊ธ€ํ†ค์ด ์•„๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํด๋ž˜์Šค์—์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

์ด๋Ÿฌํ•œ ๋ฐฉ์‹์œผ๋กœ ๋ ˆํฌ์ง€ํ† ๋ฆฌ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค๋ฉด ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ๋ ˆํฌ์ง€ํ† ๋ฆฌ ๊ฐ์ฒด ์ƒ์„ฑ๊ณผ ๊ด€๋ จํ•˜์—ฌ dataSource, Service, retrofit์„ ๋ชจ๋‘ ๊ตฌ์„ฑํ•ด์ฃผ๋Š” ์ฝ”๋“œ๊ฐ€ ํ•„์š”ํ•˜๊ฒ ๋‹ค....

 

๋งŒ์•ฝ viewModel์ด ๋” ๋งŽ์€ ๊ณณ์—์„œ ํ•„์š”ํ•˜๋‹ค๋ฉด ํ•œ๊ณณ์—์„œ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ๋งŒ๋“  ๋ทฐ๋ชจ๋ธ์„ appContainer๋กœ ์ด๋™ํ•˜๊ณ , ๊ทธ ์œ ํ˜•์˜ ์ƒˆ ๊ฐ์ฒด์— ํŒฉํ† ๋ฆฌ๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์ž‡๋”ฐ.

// T : ๋งŒ๋“ค๊ณ  ์‹ถ์€ ์–ด๋–ค ํƒ€์ž…์ด๋“  ok
// create() ๋Š” ๊ทธ ํƒ€์ž…์˜ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๋ฉ”์„œ๋“œ 
interface Factory<T> {
	fun create() : T
	}
	
// UserViewModel์šฉ Factory
class UserViewModelFactory(
    private val userRepository: UserRepository
) : Factory<UserViewModel> {
// ์—ฌ๊ธฐ์„œ T : UserViewModel
    override fun create(): UserViewModel {
        return UserViewModel(userRepository)
    }
}

๋น„๊ต

  • ๊ธฐ์กด
    • ์•กํ‹ฐ๋น„ํ‹ฐ๋‚˜ ํ”„๋ž˜๊ทธ๋จผํŠธ์—์„œ ๋ทฐ๋ชจ๋ธ ์ƒ์„ฑ
    userViewModel = UserViewModel(appContainer.userRepository)
    
    
  • ๋ณ€๊ฒฝ : Factory๋ฅผ ํ†ตํ•ด AppContainer๋กœ ๋ทฐ๋ชจ๋ธ ์ƒ์„ฑ ์ฑ…์ž„์„ ์ด๋™ํ•œ๋‹ค.
  • class AppContainer { val userViewModelFactory = UserViewModelFactory(userRepository)

ํŒฉํ† ๋ฆฌ ํŒจํ„ด

  • ๊ฐ์ฒด ์ƒ์„ฑ์„ ๋‹ด๋‹นํ•˜๋Š” ๋ณ„๋„์˜ ํด๋ž˜์Šค(ํŒฉํ† ๋ฆฌ)๋ฅผ ๋‘์–ด ๊ฐ์ฒด ์ƒ์„ฑ ๋กœ์ง์„ ์บก์Šํ™”ํ•˜๋Š” ๋””์ž์ธ ํŒจํ„ด

๋ฒ”์œ„

  • ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ ํ๋ฆ„์„ ๋„์ž…ํ•˜๋ฉฐ ๊ฐ์ฒด๊ฐ€ ํ•ด๋‹น ํ๋ฆ„์˜ ๋ฒ”์œ„์—๋งŒ ์žˆ๊ธฐ๋ฅผ ์›ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์˜ˆ๋ฅผ ๋“ค์–ด ๋กœ๊ทธ์ธ ํ๋ฆ„์—์„œ๋งŒ ์‚ฌ์šฉ๋˜๋Š” ์‚ฌ์šฉ์ž ์ด๋ฆ„๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ๋กœ ๊ตฌ์„ฑ๋  ์ˆ˜ ์žˆ๋Š” LoginUserData๋ฅผ ๋งŒ๋“ค ๋•Œ, ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž์˜ ์ด์ „ ๋กœ๊ทธ์ธ ํ๋ฆ„์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์œ ์ง€ํ•˜์ง€ ์•Š๊ณ  ๋ชจ๋“  ์ƒˆ ํ๋ฆ„์— ์ƒˆ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ถ์„ ์ˆ˜๋„ ์žˆ๋‹ค.
class LoginContainer(val userRepository: UserRepository) {

    val loginData = LoginUserData()

    val loginViewModelFactory = LoginViewModelFactory(userRepository)
}

// AppContainer contains LoginContainer now
class AppContainer {
    ...
    val userRepository = UserRepository(localDataSource, remoteDataSource)

    // LoginContainer will be null when the user is NOT in the login flow
    var loginContainer: LoginContainer? = null
}

 

ํ๋ฆ„ ๊ด€๋ จ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์žˆ์œผ๋ฉด ์ปจํ…Œ์ด๋„ˆ ๊ฐ์ฒด๋ฅผ ์–ธ์ œ ๋งŒ๋“ค๊ณ  ์‚ญ์ œํ• ์ง€ ํŒ๋‹จํ•ด์•ผํ•œ๋‹ค.

๋กœ๊ทธ์ธ ํ๋ฆ„์ด LoginActivity์— ๋…๋ฆฝ์ ์ด๋ฏ€๋กœ ์ด ์ปจํ…Œ์ด๋„ˆ์˜ ์ˆ˜๋ช… ์ฃผ๊ธฐ๋ฅผ LoginActicity์—์„œ ๊ด€๋ฆฌํ•˜๋ฉด ๋œ๋‹ค. onCreate์—์„œ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ณ , onDestroy์—์„œ ์‚ญ์ œํ•  ์ˆ˜ ์žˆ๋‹ค. 

class LoginActivity : Activity() {

 private lateinit var loginViewModel: LoginViewModel
 private lateinit var loginData: LoginUserData
 private lateinit var appContainer: AppContainer
    
    
   override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
       
        appContainer = (application as MyApplication).appContainer

        // Login flow has started. Populate loginContainer in AppContainer
        appContainer.loginContainer = LoginContainer(appContainer.userRepository)

        loginViewModel = appContainer.loginContainer.loginViewModelFactory.create()
        
        loginData = appContainer.loginContainer.loginData
    }
    
    
     override fun onDestroy() {
        // Login flow is finishing
        // Removing the instance of loginContainer in the AppContainer
        appContainer.loginContainer = null
        super.onDestroy()
    }

}

Dagger

์ข…์†ํ•ญ๋ชฉ์„ ์„ ์–ธํ•˜๊ณ , ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์ข…์†ํ•ญ๋ชฉ์„ ์–ด๋–ป๊ฒŒ ์ถฉ์กฑํ•˜๋Š”์ง€ ์ง€์ •ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ์•„๋ž˜๋ฅผ ๋นŒ๋“œ ์‹œ๊ฐ„์— ์ž๋™์œผ๋กœ ๊ตฌํ˜„ํ•ด์ค€๋‹ค.

์œ„์—์„œ ์ˆ˜๋™์œผ๋กœ ์ข…์†ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ƒ์„ฑํ•ด๋ณด๋ฉฐ , ์—ฌ๋Ÿฌ ๋ ˆํฌ์ง€ํ† ๋ฆฌ ๊ฐ์ฒด๋ฅผ ๊ตฌ์„ฑํ•  ๊ฒฝ์šฐ ์ค‘๋ณต, ๋ฐ˜๋ณตํ•ด์„œ ์ž‘์„ฑํ•ด์ค˜์•ผํ•  ์ฝ”๋“œ๊ฐ€ ๋งŽ๊ฒ ๋‹ค๊ณ  ๋Š๊ผˆ๋‹ค. ์ด๋ฅผ ํ•ด์†Œํ•ด์ฃผ๊ธฐ ์œ„ํ•ด Dagger์—์„œ๋Š” ์ˆ˜๋™์œผ๋กœ ๊ตฌํ˜„ํ•˜๋˜ ๋กœ์ง์„ ์ž๋™์œผ๋กœ ๊ตฌํ˜„ํ•ด์ค€๋‹ค.
  • ์œ„์—์„œ ์ˆ˜๋™์œผ๋กœ ๊ตฌํ˜„ํ–ˆ๋˜ AppContainer ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•ด์ค€๋‹ค.
  • AppContainer(application grapth)์—์„œ ์‚ฌ์šฉํ•˜๋Š” ํด๋ž˜์Šค์˜ ํŒฉํ† ๋ฆฌ๋ฅผ ๋งŒ๋“ค์–ด์ค€๋‹ค.
  • ๋ฒ”์œ„๋ฅผ ํ†ตํ•ด ์ข…์† ํ•ญ๋ชฉ์„ ์žฌ์‚ฌ์šฉํ• ์ง€, ์ƒˆ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค์ง€ ๊ฒฐ์ •
  • ๋กœ๊ทธ์ธ ํ๋ฆ„์„ ์ฒ˜๋ฆฌํ–ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ Dagger subcomponent๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ •ํ•œ ํ”Œ๋กœ์šฐ๋ฅผ ์œ„ํ•œ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋งŒ๋“ค์–ด์ค€๋‹ค.
    • ๋”์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์„ ๋Œ€ ๊ฐ์ฒด๋ฅผ ํ•ด์ œํ•ด์คŒ์œผ๋กœ์จ ์„ฑ๋Šฅ ํ–ฅ์ƒ
  • ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ๊ธฐ ์œ„ํ•ด ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด์˜ ๊ทธ๋ž˜ํ”„๋ฅผ ๋งŒ๋“ ๋‹ค.
    • ๊ทธ๋ž˜ํ”„์˜ ๋ชจ๋“  ํด๋ž˜์Šค์™€ ๊ด€๋ จํ•˜์—ฌ ํ•„์š”ํ•œ ์œ ํ˜•์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€์ ธ์˜ค๋Š”๋ฐ ๋‚ด๋ถ€์ ์œผ๋กœ ํŒฉํ† ๋ฆฌ ์œ ํ˜• ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑ

์˜ˆ์‹œ

UserRepository ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด UserLocalDataSource, UserRemoteDataSource๊ฐ€  ํ•„์š”ํ•˜๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. 

class UserRepository (
	private val localDataSource : UserLocalDataSource,
	private val remoteDataSource: UserRemoteDataSource
) { ... }

 

  Dagger๊ฐ€ UserRepository ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ ์ˆ˜ ์žˆ๋„๋ก @Inject ์ฃผ์„์„ UserRepository ์ƒ์„ฑ์ž์— ์ถ”๊ฐ€ํ•œ๋‹ค.

// @Inject
// 1. Dagger๊ฐ€ UserRepository ๊ฐ์ฒด๋ฅผ ์–ด๋–ป๊ฒŒ ์ƒ์„ฑํ•˜๋Š”์ง€ ์•Œ๊ฒŒ ํ•ด์ค€๋‹ค.
// 2. ์ข…์†ํ•ญ๋ชฉ์€ UserLocalDataSource ๋ฐ UserRemoteDataSource์ž„์„ ์•Œ๋ ค์ค€๋‹ค.

class UserRepository @Inject constructor(
	private val localDataSource : UserLocalDataSource,
	private val remoteDataSource:  
) { ... }

 

์ด์ œ ์ข…์†ํ•ญ๋ชฉ์„ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๋ ค์ค˜์•ผํ•œ๋‹ค. UserLocalDataSource์™€UserRemoteDataSource์—๋„ @Inject๋ฅผ ๋ถ™์—ฌ์„œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๋ ค์ค€๋‹ค.

class UserLocalDataSource @Inject constructor() { ... }
class UserRemoteDataSource @Inject constructor() { ... }

 

Dagger ๊ตฌ์„ฑ์š”์†Œ

Dagger๋Š” ์ข…์† ํ•ญ๋ชฉ์ด ํ•„์š”ํ•  ๋•Œ ๊ฐ€์ ธ์˜ฌ ์œ„์น˜๋ฅผ ์ฐพ๋Š”๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋กœ์ ํŠธ์˜ ์ข…์† ํ•ญ๋ชฉ ๊ทธ๋ž˜ํ”„๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

  1. ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ
  2. @Component๋กœ ์ฃผ์„ ์ง€์ •

โ†’ ์ด๋ฅผ ํ†ตํ•ด ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋งŒ๋“ ๋‹ค.

@Component๋กœ ์ฃผ์„์„ ์ค€ interface ๋‚ด์—์„œ ํ•„์š”ํ•œ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค(UserRepository)๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฆ‰ @Component๋Š” Dagger์—๊ฒŒ ์ด๋ ‡๊ฒŒ ๋งํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™๋‹ค.

@Component : Dagger์•ผ ๋‚˜๋Š” ์ด๋Ÿฐ ๊ฒƒ๋“ค์ด ํ•„์š”ํ•ด. ์•Œ์•„์„œ ๋งŒ๋“ค์–ด์ค„๋ž˜?
//@Component : Dagger๊ฐ€ ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„๋ฅผ ์ƒ์„ฑํ•˜๋„๋ก ํ•œ๋‹ค.
@Component(modules = [NetworkModule::class, DatabaseModule::class])
interface ApplicationGraph {
    fun repository(): UserRepository
}

 

ํ”„๋กœ์ ํŠธ ๋นŒ๋“œ ์‹œ์— Dagger๋Š” ์ž๋™์œผ๋กœ ApplicationGraph ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌํ˜„์ธ DaggerApplicationGraph๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. 

์ด๋ฅผ ํ†ตํ•ด ์ด ๊ทธ๋ž˜ํ”„๋Š” UserRepository, UserLocalDataSource, UserRemoteDataSource ํด๋ž˜์Šค ๊ฐ„์˜ ๊ด€๊ณ„๋กœ ๊ตฌ์„ฑ๋œ ์ค‘์† ํ•ญ๋ชฉ ๊ทธ๋ž˜ํ”„๋ฅผ ๋งŒ๋“ค์–ด์ค€๋‹ค.

val applicationGraph : ApplicationGraph = DaggerApplicationGraph.create()
val userRepository : UserRepository = applicationGrapgh.repotiroy()

 

Dagger๋Š” applicationGrapgh.repository() ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค   UserRepository์˜ ์ƒˆ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ ๋‹ค.

val applicationGraph: ApplicationGraph = DaggerApplicationGraph.create()

val userRepository: UserRepository = applicationGraph.repository()
val userRepository2: UserRepository = applicationGraph.repository()

assert(userRepository != userRepository2)

 

๋งŒ์•ฝ ๊ณ ์œ ํ•œ ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด??

 

๋งค๋ฒˆ UserRepository ๊ฐ์ฒด๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•  ํ•„์š”๊ฐ€ ์žˆ์„๊นŒ??

- ๋งŒ์•ฝ ๋™์ผํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์—ฌ๋Ÿฌ ๋ทฐ๋ชจ๋ธ์—์„œ ๊ณต์œ ํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฒฝ์šฐ 

- ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š”๋ฐ ๋น„์šฉ์ด ๋งŽ์ด ๋“ ๋‹ค๋Š” ์  ์„ ๊ณ ๋ คํ–ˆ์„ ๋•Œ ๋กœ์ง์— ๋งž๊ฒŒ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค!

 

์ˆ˜๋™์œผ๋กœ ์ข…์† ํ•ญ๋ชฉ์„ ๊ตฌํ˜„ํ•  ๋•Œ๋Š” ๋™์ผํ•œ UserRepository ๊ฐ์ฒด๋ฅผ ๋ทฐ๋ชจ๋ธ ํด๋ž˜์Šค์˜ ์ƒ์„ฑ์ž์— ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๊ตฌํ˜„ํ–ˆ์ง€๋งŒ Dagger์—์„œ๋Š” ๋ฒ”์œ„ ์ฃผ์„์„ ํ†ตํ•ด์„œ ๋™์ผํ•œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ• ๊ฑฐ์•ผ! ๋ผ๊ณ  ์•Œ๋ ค์ค„ ์ˆ˜ ์žˆ๋‹ค.

๋ฒ”์œ„ ์ง€์ •

// Dagger์—๊ฒŒ ์ด ๊ทธ๋ž˜ํ”„์—์„œ ๋งŒ๋“œ๋Š” @Singleton ๊ฐ์ฒด๋“ค์€ ์•ฑ์ด ์‚ด์•„์žˆ๋Š” ๋™์•ˆ 
// ๋”ฑ! ํ•˜๋‚˜๋งŒ ๋งŒ๋“ค์–ด์„œ ์žฌ์‚ฌ์šฉํ•ด์ค˜ ๋ผ๊ณ  ๋งํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™๋‹ค.

@Singleton
@Component 
interface ApplicationGraph {
	fun repository() : UserRepository
}

 

UserRepository๋ฅผ ์•ฑ ์ „์ฒด์—์„œ ๋”ฑ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๋งŒ๋“ค์–ด์ค€๋‹ค. 

์ด๋ฅผ ํ†ตํ•ด ๋ทฐ๋ชจ๋ธ์—์„œ UserRepostory๋กœ ์ž‘์—… ์‹œ์— ์ผ๊ด€๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. 

@Singleton
class UserRepository @Inject constructor(
    private val localDataSource: UserLocalDataSource,
    private val remoteDataSource: UserRemoteDataSource
) { ... }
์ด ํŒŒํŠธ์—์„œ๋Š” ์ข…์† ํ•ญ๋ชฉ ๊ทธ๋ž˜ํ”„๋ฅผ ๊ทธ๋ ค๋‚˜๊ฐ€๋ฉด์„œ, ํ•„์š”ํ•œ ๋ฒ”์œ„๋ฅผ ์ƒ๊ฐํ•ด๋ณด๋ฉด ์ข‹๊ฒ ๋‹ค. ๋ฌดํ„ฑ๋Œ€๋กœ ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ ๋ณด๋‹ค๋Š” ์ ์ ˆํ•œ ๋ฒ”์œ„๋ฅผ ์ง€์ •ํ•ด๋ณด์ž!

Android์—์„œ Dagger๋ฅผ ์‚ฌ์šฉํ•ด๋ณด์ž!

๊ถŒ์žฅ ์‚ฌํ•ญ

- ๊ฐ€๋Šฅํ•˜๋ฉด ์ƒ์„ฑ์ž ์‚ฝ์ž…์„ ํ•˜๊ณ  ๊ฐ€๋Šฅํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ํ•˜์ž

- @Binds -> ์ธํ„ฐํŽ˜์ด์Šค ํ˜•ํƒœ์˜ ์ข…์† ํ•ญ๋ชฉ ์‚ฝ์ž…์œผ๋กœ ์ธํ„ฐํŽ˜์ด์Šค์— ์–ด๋–ค ๊ตฌํ˜„์ด ์žˆ์–ด์•ผํ•˜๋Š”์ง€ ์•Œ๋ ค์ฃผ๊ธฐ

- @Provides -> ํ”„๋กœ์ ํŠธ๊ฐ€ ์†Œ์œ ํ•˜์ง€ ์•Š์€ ํด๋ž˜์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๋ ค์ค€๋‹ค.

- ์‚ฌ์šฉ๋˜๋Š” ์ „์ฒด ๊ธฐ๊ฐ„์— ๋”ฐ๋ผ ๋ฒ”์œ„๋ฅผ ์ง€์ •ํ•ด์ค€๋‹ค

 

// 1. ์•ฑ์˜ ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„ ์ •์˜ 
@Component
interface ApplicaitionComponent {...}


// Application์˜ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ณต์œ ํ•˜๊ธฐ ์œ„ํ•ด appComponent๋ฅผ Application์— ๋‘”๋‹ค.
class Application : Application() {
	val appComponent = DaggerApplicationComponent.create()
}

 

์•กํ‹ฐ๋น„ํ‹ฐ๋‚˜ ํ”„๋ž˜๊ทธ๋จผํŠธ์™€ ๊ฐ™์€ ํด๋ž˜์Šค๋Š” ์‹œ์Šคํ…œ์— ์˜ํ•ด ์ธ์Šคํ„ด์Šคํ™”๋˜๊ธฐ ๋•Œ๋ฌธ์— Dagger๊ฐ€ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์—†๋‹ค. 

๋”ฐ๋ผ์„œ ์•กํ‹ฐ๋น„ํ‹ฐ๋‚˜ ํ”„๋ž˜๊ทธ๋จผํŠธ์—์„œ๋Š” ํ•„๋“œ ์‚ฝ์ž…์„ ํ†ตํ•ด์„œ ํ•„์š”ํ•œ ์ข…์† ํ•ญ๋ชฉ์„ ์•Œ๋ ค์ค„ ์ˆ˜ ์žˆ๋‹ค.

 

Activity, Fragment, Service, BroadcastReceiver, ContentProvider , ์ฆ‰ ์•ˆ๋“œ๋กœ์ด๋“œ ํ”„๋ ˆ์ž„์›Œํฌ ํด๋ž˜์Šค์—์„œ ์ƒ์„ฑ์ž ์‚ฝ์ž…์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค!! ๋”ฐ๋ผ์„œ  ํ•„๋“œ ์‚ฝ์ž…์„ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค.

class UserFragment : Fragment()  {

	@Inject lateinit var userViewModel : UserViewModel

}

 

์•กํ‹ฐ๋น„ํ‹ฐ์—์„œ ๋ทฐ๋ชจ๋ธ ๊ฐ์ฒด๋ฅผ ์ œ๊ณต๋ฐ›๊ธฐ ์œ„ํ•ด์„œ๋Š”

@Component
interface ApplicationComponent {
	
    fun inject(activity : LoginActivity)
    // Dagger์—๊ฒŒ  " LoginActivity๊ฐ€ ์ฃผ์ž…์„ ์š”์ฒญํ•˜๊ณ  ์žˆ์–ด. 
    // ๊ทธ๋Ÿฌ๋‹ˆ๊นŒ ๊ทธ๋ž˜ํ”„๋Š” ์•กํ‹ฐ๋น„ํ‹ฐ๊ฐ€ ์š”์ฒญํ•˜๋Š” ๋ชจ๋“  ํ•„๋“œ์˜ ์˜์กด์„ฑ์„ ๋งŒ์กฑํ•ด์•ผํ•ด!" 
    
    // ์•กํ‹ฐ๋น„ํ‹ฐ๊ฐ€ ๊ทธ๋ž˜ํ”„์— ์ ‘๊ทผํ•˜๊ธธ ์›ํ•˜๋ฉฐ ์‚ฝ์ž…์„ ์š”์ฒญํ•œ๋‹ค๊ณ  Dagger์—๊ฒŒ ์•Œ๋ ค์ค€๋‹ค. 

}

 

class LoginActivity : Activity() {

	// ๋ทฐ๋ชจ๋ธ ๊ฐ์ฒด 
    // ์ข…์† ํ•ญ๋ชฉ ๊ทธ๋ž˜ํ”„๋ฅผ ํ†ตํ•ดLoginViewModel ๊ฐ์ฒด๋ฅผ ๋ฐ›๊ณ  ์‹ถ์–ด์š”! ๋ผ๊ณ  Dagger์—๊ฒŒ ์š”์ฒญํ•˜๋Š” ๊ฒƒ
    @Inject lateinit var loginViewModel : LoginViewModel


	override fun onCreate(savedInstanceState: Bundle?) {
        
        (applicationContext as Application).appComponent.inject(this)
        
        /*
        	1. Dagger์•ผ , LoginActivity์˜ @Inject ํ•„๋“œ ๋“ค์„ ์ดˆ๊ธฐํ™”ํ•ด์ค˜
            2. ์‹ค์ œ๋กœ ์ฃผ์ž… 
            3. ์ด์ œ loginViewModel ์‚ฌ์šฉ ๊ฐ€๋Šฅ 
        
        */ 

        super.onCreate(savedInstanceState)
    }

}

 

@Inject : Dagger์•ผ, LoginViewModel์€ ์ด๋ ‡๊ฒŒ ๋งŒ๋“ค๋ฉด ๋ผ! 

class LoginViewModel @Inject constructor(
    private val userRepository: UserRepository
)

 

๊ทธ๋Ÿฌ๋ฉด Dagger๋Š” ๋ ˆํ† ์ง€ํ† ๋ฆฌ ๊ฐ์ฒด๋ฅผ  ๊ตฌ์„ฑํ•˜๋ ค๊ณ  ํ•  ๊ฒƒ์ด๊ณ , ์ด์— ๋”ฐ๋ผ ํ•„์š”ํ•œ UserLocalDataSource, UserRemoteDataSource ๊ฐ์ฒด๋“ค์„ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ Dagger์—๊ฒŒ ์•Œ๋ ค์ค˜์•ผํ•œ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด์„œ๋Š” @Inject constructor (...)์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

๋ชจ๋“ˆ

UserRemoteDataSource์—๋Š” ๋ ˆํŠธ๋กœํ•์ด ์‚ฌ์šฉ๋œ๋‹ค. ๋ ˆํŠธ๋กœํ• ๊ฐ์ฒด ๊ตฌ์„ฑ์„ ์œ„ํ•ด์„œ๋Š” ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šคํ™”๊ฐ€ ์•„๋‹Œ Retrofit.Builder()๋ฅผ ํ˜ธ์ถœํ•ด์•ผํ•œ๋‹ค.

์ด ๋•Œ๋Š” @Inject ๋Œ€์‹  @Module์„ ํ†ตํ•ด Dagger์—๊ฒŒ ์ด ํด๋ž˜์Šค๋Š” Dagger ๋ชจ๋“ˆ์ด์•ผ ๋ผ๊ณ  ์•Œ๋ ค์ค„ ์ˆ˜ ์žˆ๋‹ค.

@Module 
class NetworkModule {...}

 

์—ฌ๊ธฐ์„œ ๋ชจ๋“ˆ์€ ๊ฐ์ฒด๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์บก์Šํ™”ํ•œ ๊ฒƒ์ด๋‹ค. 

์•„๋ž˜์—์„œ๋Š” ๋„คํŠธ์›Œํ‚น ๊ด€๋ จ ๊ฐ์ฒด๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋กœ์ง์„ ๊ทธ๋ฃนํ™”ํ•˜๊ธฐ ์œ„ํ•ด NetworkModule ํด๋ž˜์Šค๋ฅผ ํ˜ธ์ถœํ–ˆ๋‹ค. 

// 1. Dagger ๋ชจ๋“ˆ์ด์•ผ 
@Module
class NetworkModule {
	
    // 2. ์ด ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ํƒ€์ž…์˜ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ๋ผ
    // ํ”„๋กœ์ ํŠธ๊ฐ€ ์†Œ์œ ํ•˜์ง€ ์•Š์€ ํด๋ž˜์Šค(ex. retrofit, okHttpClient, Gson ๋“ฑ) ๊ฐ์ฒด๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๋ ค์ค€๋‹ค.
	@Provides
    fun provideLoginRetrofitService(
    	okHttpClient : OkHttpClient
    ) : LoginRetrofitService {
    	return Retrofit.Builder()
        		.baseUrl("https://example.com")
                .build()
               
                .create(LoginService::class.java) 
    } 
    
  
}

 

์ด๋ ‡๊ฒŒ ๋ชจ๋“ˆ์„ ์ •์˜ํ•ด์ค€ ํ›„ Dagger ๊ทธ๋ž˜ํ”„๊ฐ€ ์ด ๋ชจ๋“ˆ์— ๊ด€ํ•ด ์•Œ ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด @Component ์ธํ„ฐํŽ˜์ด์Šค์— ๋ชจ๋“ˆ์„ ์ถ”๊ฐ€ํ•ด์ค˜์•ผํ•œ๋‹ค.

 

// modules:  ๊ทธ๋ž˜ํ”„๋ฅผ ๊ตฌ์„ฑํ•  ๋•Œ ํฌํ•จ๋˜์–ด์•ผํ•  ๋ชจ๋“ˆ์„ ์•Œ๋ ค์ฃผ๋Š” ์—ญํ•  
@Component(modules = [NetworkModule::class])
interface ApplicationComponent {...}

 

 

LoginActivity๋Š” LoginViewModel์ด ํ•„์š”ํ•˜๋‹ค. Dagger๋Š” LoginViewModel & ์ข…์† ํ•ญ๋ชฉ์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋‹ด์€ ๊ทธ๋ž˜ํ”„๋ฅผ ๋นŒ๋“œํ•œ๋‹ค. 

Dagger๋Š” ํด๋ž˜์Šค ์ƒ์„ฑ์ž์˜ @Inject๋Š” ํ†ตํ•ด ๋ฐฉ๋ฒ•์„ ์•Œ๊ณ  ์žˆ๋‹ค. ์ƒ์„ฑํ•œ ApplicationComponent ๋‚ด์—๋Š” ์ œ๊ณต ๋ฐฉ๋ฒ•์„ ์•Œ ๊ณ  ์žˆ๋Š” ๋ชจ๋“  ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋‹ค. ๋˜ํ•œ LoginRetrofitService ๊ฐ์ฒด๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด NetworkModule์„ ํฌํ•จํ•˜๊ณ  ์žˆ๋‹ค.

๋ฒ”์œ„

@Singleton
@Component(modules = [NetworkModule::class])
interface ApplicationComponent {
	fun inject(activity : LoginActivity)
}

@Singleton
class UserRepository @Inject constructor(
    private val localDataSource: UserLocalDataSource,
    private val remoteDataSource: UserRemoteDataSource
) { ... }


@Module
class NetworkModule {
	
    @Singleton
    @Provides
    fun provideLoginRetrofitService(): LoginRetrofitService { ... }

}

์›ํ•˜๋Š” Scope๋กœ ๊ตฌ์„ฑํ•ด๋ณด์ž

๋กœ๊ทธ์ธ ํ๋ฆ„์„ ๊ตฌ์„ฑํ•˜๋Š” ํ™”๋ฉด์ด ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํ”„๋ž˜๊ทธ๋จผํŠธ๋กœ ๋˜์–ด์žˆ๋‹ค๋ฉด ๋กœ๊ทธ์ธ ํ๋ฆ„์˜ ํ”„๋ž˜๊ทธ๋จผํŠธ์—์„œ๋Š” ๋™์ผํ•œ LoginViewModel ๊ฐ์ฒด๋ฅผ ์žฌ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ๋กœ๊ทธ์ธ ํ๋ฆ„์ด ์™„๋ฃŒ๋œ ํ›„์—๋Š” ์–ด๋–จ๊นŒ?

๋กœ๊ทธ์ธ ํ๋ฆ„์ด ๋๋‚ฌ๋‹ค๋ฉด ์ด์ œ ๋”์ด์ƒ LoginViewModel์ด ๋‚จ์•„์žˆ์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

๊ฐ ๋กœ๊ทธ์ธ ํ๋ฆ„๋งˆ๋‹ค , ๋‹ค์‹œ ๋งํ•ด ๋กœ๊ทธ์ธ ํ๋ฆ„์— ๋Œ€ํ•ด์„œ ๋‹ค๋ฅธ LoginViewModel ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•„์š”ํ•˜๋‹ค.  ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์•„์›ƒํ•œ ๊ฒฝ์šฐ์—๋Š” ์ฒ˜์Œ ๋กœ๊ทธ์ธํ–ˆ์„ ๋•Œ์™€๋Š” ๋‹ค๋ฅธ ๋ทฐ๋ชจ๋ธ ๊ฐ์ฒด๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

์‹ฑ๊ธ€ํ†ค์œผ๋กœ ๊ตฌํ˜„ ์‹œ์—๋Š” ์ด์ „ ๋กœ๊ทธ์ธ ์ •๋ณด๊ฐ€ ๋‚จ์•„์žˆ๊ฑฐ๋‚˜ ์ด์ „ ๋ฐ์ดํ„ฐ๋‚˜ ๋‚จ์•„์žˆ์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด์„œ  ๋ทฐ๋ชจ๋ธ์˜ ๋ฒ”์œ„๋ฅผ LoginActicity์˜ ์ˆ˜๋ช… ์ฃผ๊ธฐ๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๋”ฐ๋ผ์„œ ์ด๋Ÿฐ ๊ฒฝ์šฐ๋ผ๋ฉด ๋กœ๊ทธ์ธ ์ „์šฉ Scope๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๋ฉด ๋œ๋‹ค.

@Component
interface LoginComponent {}

 

LoginActivity๋Š” ๋กœ๊ทธ์ธ ๋ณ„ ๊ตฌ์„ฑ์ด ์žˆ์œผ๋ฏ€๋กœ LoginComponent์—์„œ ์ข…์† ํ•ญ๋ชฉ์„ ๋ฐ›์•„์•ผํ•œ๋‹ค.

@Component
interface LoginComponent {
	fun inject(activity : LoginActivity)
}

 

LoginActivity๋Š” LoginViewModel์ด ํ•„์š”ํ•˜๋‹ค. ์ด ๋•Œ LoginViewModel์€ UserRepository์— ์ข…์†๋˜๊ธฐ ๋•Œ๋ฌธ์— LoginComponent๋Š” ApplicationComponent์˜ ๊ฐ์ฒด์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์–ด์•ผํ•œ๋‹ค. ์ด ๋•Œ Dagger์˜ SubComponent๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ƒˆ ๊ตฌ์„ฑ์š”์†Œ๊ฐ€ ๋‹ค๋ฅธ ๊ตฌ์„ฑ ์š”์†Œ์˜ ์ผ๋ถ€๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด @SubComponent์ด๋‹ค.

์—ฌ๊ธฐ์„œ ํ•˜์œ„ ๊ตฌ์„ฑ์š”์†Œ๋Š” ์ƒ์œ„ ๊ตฌ์„ฑ ์š”์†Œ์˜ ๊ฐ์ฒด ๊ทธ๋ž˜ํ”„๋ฅผ ์ƒ์† ๋ฐ ํ™•์žฅํ•˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ์ด๋‹ค.  ๋”ฐ๋ผ์„œ ์ƒ์œ„ ๊ตฌ์„ฑ์š”์†Œ์— ์ œ๊ณต๋œ ๋ชจ๋“  ๊ฐ์ฒด๋Š” ํ•˜์œ„ ๊ตฌ์„ฑ์š”์†Œ์—๋„ ์ œ๊ณต๋œ๋‹ค. ์ฆ‰ ApplicationComponent์— ์ œ๊ณต๋œ ๋ชจ๋“  ๊ฐ์ฒด๋Š” LoginComponent์—๋„ ์ œ๊ณต๋˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

// @SubComponent : Dagger์—๊ฒŒ ์ด ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ํ•˜์œ„ ๊ตฌ์„ฑ ์š”์†Œ์ž„์„ ์•Œ๋ ค์ค€๋‹ค.
@SubComponent
interface LoginComponent {
	fun inject(loginActivity: LoginActivity)
}

 

๋˜ํ•œ ApplicationComponent๊ฐ€ LoginComponent์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ ์ˆ˜ ์žˆ๋„๋ก ์•„๋ž˜์™€ ๊ฐ™์ด ํ•˜์œ„ ๊ตฌ์„ฑ์š”์†Œ ํŒฉํ† ๋ฆฌ๋ฅผ ์ •์˜ํ•ด์ค€๋‹ค.

@Subcomponent
interface LoginComponent {

	@Subcomponent.Factory
    interface Factory {
    	fun create() : LoginComponent
    }
    
    fun inject(loginActivity: LoginActivity)
}

 

๊ทธ๋ฆฌ๊ณ  LoginComponent๊ฐ€ ApplicationComponent์˜ ํ•˜์œ„ ๊ตฌ์„ฑ ์š”์†Œ์ž„์„ Dagger์—๊ฒŒ ์•Œ๋ ค์ค€๋‹ค.

 

1. ๋จผ์ € ํ•˜์œ„ ๊ตฌ์„ฑ ์š”์†Œ ํด๋ž˜์Šค๋ฅผ subcomponents ์†์„ฑ์— ์ „๋‹ฌํ•˜๋Š” ์ƒˆ๋กœ์šด ๋ชจ๋“ˆ์„ ๋งŒ๋“ค์–ด์ค€๋‹ค.

@Module(subcomponents = LoginComponent::Class)
class SubComponentModule {}

 

2. ์ƒˆ ๋ชจ๋“ˆ์„ ApplicationComponent์— ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.

@Singleton
@Component(modules = [NetworkModule::Class, SubComponentsModule::Class])
interface ApplicationComponent { ... }

 

์ด์ œ LoginActivity์— ์ข…์†ํ•ญ๋ชฉ์„ ์ฃผ์ž…ํ•˜๋Š” ๊ฒƒ์€ ApplicationComponent๊ฐ€ ์•„๋‹Œ LoginComponent์ด๊ธฐ ๋•Œ๋ฌธ์— ApplicationComponent ๋‚ด๋ถ€ inject() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ญ์ œํ•  ์ˆ˜ ์žˆ๋‹ค.

๋Œ€์‹  LoginComponent ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํŒฉํ† ๋ฆฌ๋ฅผ ํ˜ธ์ถœํ•ด์ค€๋‹ค.

@Singleton
@Component(modules = [NetworkModule::class, SubcomponentsModule::Class])
interface ApplicationComponent {
	// fun inject(activity : LoginActivity) -> ์‚ญ์ œ 
    
    fun loginComponent() : LoginComponent.Factory
}

 

LoginComponent์˜ ๋ฒ”์œ„๋Š”?

LoginComponent๋ฅผ ๋งŒ๋“ค์—ˆ๋˜ ์ด์œ ๋Š”

1. ๋กœ๊ทธ์ธ ํ๋ฆ„ ์ค‘ ๋™์ผํ•œ LoginViewModel ์ธ์Šคํ„ด์Šค๋ฅผ ๊ณต์œ ํ•˜๊ธฐ ์œ„ํ•จ

2, ๊ฐ ๋กœ๊ทธ์ธ ํ๋ฆ„๋งˆ๋‹ค๋Š” ๋‹ค๋ฅธ ๋ทฐ๋ชจ๋ธ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•จ

์ด์—ˆ๋‹ค. ๋”ฐ๋ผ์„œ LoginComponent์˜ ์ ์ ˆํ•œ ๊ธฐ๊ฐ„์€ LoginActivity์™€ ๋™์ผํ•˜๋‹ค. ๋ชจ๋“  ์ƒˆ ํ™œ๋™์—๋Š” LoginComponent์˜ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค์™€ ์ด๋Ÿฌํ•œ ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋ž˜๊ทธ๋จผํŠธ๊ฐ€ ํ•„์š”ํ•˜๋‹ค. 

 

์ด๋ ‡๊ฒŒํ•จ์œผ๋กœ์จ LoginComponent๋Š” LoginActivity์˜ ์ˆ˜๋ช…์ฃผ๊ธฐ์™€ ์—ฐ๊ฒฐ๋œ๋‹ค. 

class LoginActivity : Activity() {
	// ๋กœ๊ทธ์ธ ๊ทธ๋ž˜ํ”„์— ๋Œ€ํ•œ ์ฐธ์กฐ
	lateinit var loginComponent : LoginComponent

}

 

ApplicationComponent๋ฅผ ์‚ฌ์šฉํ•ด์„œ LoginComponent์˜ ์ฐธ์กฐ๋ฅผ ๊ฐ€์ ธ์˜จ ํ›„ ๋ณ€์ˆ˜์— ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค.

class LoginActivity: Activity() {

    lateinit var loginComponent: LoginComponent
    
    // ๋กœ๊ทธ์ธ ๊ทธ๋ž˜ํ”„์— ์˜ํ•ด์„œ ์ฃผ์ž…๋˜์–ด์•ผํ•˜๋Š” ํ•„๋“œ 
    @Inject lateinit var loginViewModel : LoginViewModel
    
     override fun onCreate(savedInstanceState: Bundle?) {
     
     // application ๊ทธ๋ž˜ํ”„๋ฅผ ์ด์šฉํ•ด์„œ ๋กœ๊ทธ์ธ ๊ทธ๋ž˜ํ”„๋ฅผ ๋งŒ๋“ ๋‹ค.
     	loginComponent = (applicationContext as Application).appComponent.loginComponent().create()
       
     // ๋กœ๊ทธ์ธ ์•กํ‹ฐ๋น„ํ‹ฐ์—์„œ @Inject ํ•„๋“œ๋“ค์„ ์ดˆ๊ธฐํ™”ํ•ด์ค€๋‹ค. -> ์‚ฝ์ž… -> ๋ทฐ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•  ์žˆ๋‹ค.
       loginComponent.inject(this)

        super.onCreate(savedInstanceState)
    }
    
}

 

์ด ์ฏค์—์„œ ๊ตฌ์กฐ๋ฅผ ํ•œ๋ฒˆ ์ •๋ฆฌํ•ด๋ณด๋ฉด 

- Application Scope

  • ApplicationComponent : ์•ฑ ์ „์ฒด์˜ ์‹ฑ๊ธ€ํ†ค ์˜์กด์„ฑ ๊ด€๋ฆฌ 
  • NetworkModule(OkhttpClient, Retrofit)๊ณผ ๊ฐ™์€ ์ „์—ญ์ ์œผ๋กœ ํ•„์š”ํ•œ ์˜์กด์„ฑ ํฌํ•จ

- LoginFlow Scope

  • LoginComponent๋Š” ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ๋งŒ ๋‹ด๋‹น
  • LoginViewModel์€ ์ด scope์•ˆ์—์„œ๋งŒ ์กด์žฌ
  • ๋ชจ๋“  ๋กœ๊ทธ์ธ ํ๋ฆ„๊ณผ ๊ด€๋ ค๋œ ํ™”๋ฉด๋“ค์€ ๋ทฐ๋ชจ๋ธ ๊ณต์œ 

LoginViewModel์ด ํ•„์š”ํ•œ ๋‘๊ฐœ์˜ ํ”„๋ž˜๊ทธ๋จผํŠธ๊ฐ€ ์žˆ๋‹ค๋ฉด ๋‘ ํ”„๋ž˜๊ทธ๋จผํŠธ ๋ชจ๋‘ ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค์™€ ํ•จ๊ป˜ ์ œ๊ณต๋œ๋‹ค.

@ActivityScope
@SubComponent
interface LoginComponent {
	
    @Subcomponent.Factory
    interface Factory {
    	fun create(): LoginComponent
    }	
    
   // LoginActivity , LoginUsernameFragment , LoginPasswordFragment ๋“ฑ 
   // ๋กœ๊ทธ์ธ๊ณผ ๊ด€๋ จ๋œ ๋ชจ๋“  ํ™”๋ฉด๋“ค์€ LoginComponent์— ์˜์กด์„ฑ ์ฃผ์ž…์„ ์š”์ฒญํ•œ๋‹ค.
   fun inject(loginActivity : LoginActivity)
   fun inject(usernameFragment : LoginUsernameFragment)
   fun inject(passwordFragment : LoginPasswordFragment)
   
}

 

์ด์ œ LoginUsernameFragment์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฒ•์„ ๋ณด์ž

class LoginUsernameFragment: Fragment() {
	// ๋กœ๊ทธ์ธ ๊ทธ๋ž˜ํ”„๋กœ๋ถ€ํ„ฐ ์ฃผ์ž…๋˜์–ด์•ผํ•˜๋Š” ํ•„๋“œ
    @Inject lateinit var loginViewModel : LoginViewModel
    
     override fun onAttach(context: Context) {
        super.onAttach(context)
        
        // 1. LoginActivity๋กœ๋ถ€ํ„ฐ login๊ทธ๋ž˜ํ”„ ๊ฐ€์ ธ์˜ค๊ธฐ 
        // 2. ๊ทธ๋ž˜ํ”„๋ฅผ ์‚ฌ์šฉํ•ด์„œ @Inject ํ•„๋“œ๋“ค์„ ์ดˆ๊ธฐํ™”ํ•˜๊ธฐ
        
        (activity as LoginActivity).loginComponent.inject(this)
        
        // ์ด์ œ loginViewModel์— ์ ‘๊ทผ ๊ฐ€๋Šฅ, onCreateView์—์„œ๋„ ์ ‘๊ทผ ๊ฐ€๋Šฅ,

Hilt 

Dagger์™€ Hilt์˜ ์ฐจ์ด 

  • ์ฝ”๋“œ๋กœ ์‚ดํŽด๋ณด๊ธฐ
// Dagger

// Hilt

 

 

 

728x90