Android/Kotlin

안드로이드 Retrofit + MVVM + Repository + Dagger

easy-1 2021. 10. 20. 15:39

<개요>

Retrofit 을 이용한 서버통신을 할 때 MVVM + Repository  + Dagger 를 적용하여 구현

<적용방법>

1. SignActivity

2. SignViewModel

3. SignModel

4. RetrofitService

5. NetworkModule

6. SignRepository

7. SignRepositoryImpl

 

<예제>

uid 값을 서버에 전송하고 success 값을 받아오는 예제

 

1) SignActivity.kt

- Activity 에서 ViewModel 을  등록

- userInfo 데이터를 Observe 하며 반응형 프로그래밍 작업

@AndroidEntryPoint
class SignActivity : AppCompatActivity() {

    private lateinit var binding: ActivitySignBinding
    private val viewModel by viewModels<SignViewModel>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_sign)

        // Set Observer
        observerViewModel()
        
        viewModel.apiUserInfo()
    }
    
    
    // Set Observer
    fun observerViewModel() {

        viewModel.apply {
                userInfo.observe(this@SignActivity, Observer {
                Dlog.d("userInfo :: ${Gson().toJson(it)}")
            })
        }
    }
}

2) SignViewModel.kt

-  관찰할 MutableLiveData userInfo  선언

- _userInfo 에 value 해줌으로써 userInfo  데이터 값이 변경됨

- Retrofit 을 이용한 서버 통신 후 Repository 에 저장된 데이터를 _userInfo  에 value 해줌

@HiltViewModel
class SignViewModel @Inject constructor(
    private val service: RetrofitService
) : ViewModel() {

    private val _userInfo: MutableLiveData<UserInfo> = MutableLiveData()
    val userInfo: LiveData<UserInfo>
        get() = _userInfo

    // Retrofit을 이용하여 Repository에 저장된 데이터 가져오기 
    fun apiUserInfo() {
        viewModelScope.launch {
            val response = SignRepositoryImpl(service).getUserInfo(uid)
            .awaitResponse()
            if (response.isSuccessful) {

                val data = response.body()

                withContext(Main) {
                    if (data != null) {
                        Dlog.d("data :: ${Gson().toJson(data)}")
                        _userInfo.value = data
                    }
                }
            } else {
                Dlog.d("failed :: ${response.message()}")
            }
        }
    }
}

3) SignModel.kt

- Retrofit 을 이용한 서버통신 후  받아오는 리스폰값

data class UserInfo(
    @SerializedName("success")
    var success: Boolean = false,
)

4) RetrofitService.kt

- Retrofit 에 이용되는 interface

interface RetrofitService {

    companion object {
        const val BASE_URL =
            "https://test.net/"
    }

    @FormUrlEncoded
    @POST("userInfo.php")
    fun get_userInfo(
        @Field("uid") uid: String? = "",
    ): Call<UserInfo>
}

5) NetworkModule.kt

- Dagger 를 이용한 Retrofit 추가 설정

@Module
@InstallIn(SingletonComponent::class) //전체 application 에서 사용되는 모듈
object NetworkModule {


    @Provides
    @Singleton
    fun provideRetrofitRepository(retrofit: Retrofit): RetrofitService {
        return retrofit.create(RetrofitService::class.java)
    }


    @Provides
    @Singleton
    fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl(RetrofitService.BASE_URL)
            .client(okHttpClient)
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .build()
    }


    @Provides
    @Singleton
    fun provideOkHttpClient(interceptors: ArrayList<Interceptor>): OkHttpClient {
        val clientBuilder = OkHttpClient
            .Builder()
            .followRedirects(false)
        interceptors.forEach {
            clientBuilder.addInterceptor(it)
        }
        return clientBuilder.build()
    }


    @Provides
    @Singleton
    fun provideInterceptors(): ArrayList<Interceptor> {
        val interceptors = arrayListOf<Interceptor>()
        val loggingInterceptor = HttpLoggingInterceptor().apply {
            level = if (BuildConfig.DEBUG) {
                HttpLoggingInterceptor.Level.BODY
            } else {
                HttpLoggingInterceptor.Level.NONE
            }
        }
        interceptors.add(loggingInterceptor)
        return interceptors
    }
}

6) SignRepository.kt

- Retrofit 통신 후 콜백 받아오는 Repository

interface SignRepository {

    suspend fun getUserInfo(
        uid: String? = "",
    ): Call<UserInfo>
}

7) SignRepositoryImpl.kt

- Repository 를 사용하여 구현

class SignRepositoryImpl @Inject constructor(
    val service: RetrofitService
) : SignRepository {

    override suspend fun getUserInfo(
        uid: String?,
    ): Call<UserInfo> {
        return service.get_userInfo(uid)
    }
}