레트로핏 예제 포스팅에서 클래스명 등 좀 바뀌었다.
//
/**
* Repository that fetch search query data from kakaoImageApi.
*/
interface ImageSearchRepository {
/** Fetches search query data from kakaoImageApi */
suspend fun searchImage(
query: String,
sort: String? = null,
page: Int? = null,
size: Int? = null
): Response<KakaoData>
}
/**
* Network Implementation of Repository that fetch search query data from kakaoImageApi.
*/
class NetworkImageSearchRepository(
private val kakaoImageApiService: KakaoImageApiService
) : ImageSearchRepository {
/** Fetches search query data from kakaoImageApi*/
override suspend fun searchImage(
query: String,
sort: String?,
page: Int?,
size: Int?
): Response<KakaoData> = kakaoImageApiService.searchImage(query, sort, page, size)
}
//
/*
DefaultAppContainer의 인스턴스는 애플리케이션 클래스에 들어있어야 하는데
뷰모델 팩토리에서 저장소 인자 넣을 때 this[APPLICATION_KEY] as KakaoImageSearchApplication 이렇게 접근해서
애플리케이션의 container의 저장소를 넘겨주는데,
as KakaoImageSearchApplication 캐스팅 할 때 터진다.
컴포즈 관련인지 뭔지 모르겠음. 그냥 전역으로 만들어뒀다.
*/
/**
* Dependency Injection container at the application level.
*/
interface AppContainer {
val imageSearchRepository: ImageSearchRepository
}
/**
* Implementation for the Dependency Injection container at the application level.
*
* Variables are initialized lazily and the same instance is shared across the whole app.
*/
class DefaultAppContainer : AppContainer {
private val baseUrl = "https://dapi.kakao.com"
private fun createOkHttpClient(): OkHttpClient {
val interceptor = HttpLoggingInterceptor()
if (BuildConfig.DEBUG)
interceptor.level = HttpLoggingInterceptor.Level.BODY
else
interceptor.level = HttpLoggingInterceptor.Level.NONE
return OkHttpClient.Builder().also {
it.connectTimeout(20, TimeUnit.SECONDS)
it.readTimeout(20, TimeUnit.SECONDS)
it.writeTimeout(20, TimeUnit.SECONDS)
it.addNetworkInterceptor(interceptor)
}.build()
}
/**
* Use the Retrofit builder to build a retrofit object using a GsonConverterFactory
*/
private val retrofit: Retrofit = Retrofit.Builder().also {
it.addConverterFactory(GsonConverterFactory.create())
it.baseUrl(baseUrl)
it.client(createOkHttpClient())
}.build()
/**
* Retrofit service object for creating api calls
*/
private val retrofitService: KakaoImageApiService by lazy {
retrofit.create(KakaoImageApiService::class.java)
}
/**
* DI implementation for Mars photos repository
*/
override val imageSearchRepository: ImageSearchRepository by lazy {
NetworkImageSearchRepository(retrofitService)
}
}
// 원래는 Application 클래스에 있는 변수.
/** AppContainer instance used by the rest of classes to obtain dependencies */
val myContainer: AppContainer = DefaultAppContainer()
// 뷰모델에 파라미터 추가
(private val imageSearchRepository: ImageSearchRepository)
// 팩토리는 컴패니언 오브젝트로.
/**
* Factory for [ImageSearchViewModel] that takes [ImageSearchRepository] as a dependency
*/
companion object {
val Factory: ViewModelProvider.Factory = viewModelFactory {
initializer {
ImageSearchViewModel(imageSearchRepository = myContainer.imageSearchRepository)
}
}
}
// 프래그먼트에서 뷰모델 생성할 때 팩토리 넣는 법:
private val viewModel: ImageSearchViewModel by viewModels { ImageSearchViewModel.Factory }
// 뷰모델에서 searchImage 사용 방법:
imageSearchRepository.searchImage(query, sort, page, size)
아직도 잘 모르겠다..
참고