오늘도 삽질중

Android retrofit Rxjava httpCode 확장함수로 편하게 처리하기 본문

안드로이드

Android retrofit Rxjava httpCode 확장함수로 편하게 처리하기

Choi3950 2020. 11. 5. 18:37
반응형

Rx로 레트로핏 네트워크 통신시 HttpCode를 확장함수로 처리해보자.




회사 프로젝트의 네트워크통신을 Rx로 변경하고 있다.

물론 기본적인 방법으로도 httpCode를 가져 올수는 있지만 매번 호출마다 subscribe에서 분기처리를 해줘야 하니 뭔가 영 마음에 들지 않았다.


우선 httpCode를 받아와야 하니 당연히 Single<Response<T>> 를 리턴하는 api 가 존재할것이다.

@FormUrlEncoded
@POST("login/Auth")
fun loginApiPhoneSignIn(@FieldMap map: Map<String,String> ) : Single<Response<LoginDataEntity>>



그 다음엔 api를 호출하여 보통 이런식으로 처리를 했었다.

compositeDisposable.add(
loginUseCase.phoneSignIn(apiBodyMap)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe { }
.doOnError { }
.doOnSuccess { }
.subscribe({

val httpCode = it.code()

when(httpCode) {
200 -> {
val loginData = it.body()
//.....
//....

}
300 -> {

}
400 -> {

}
//......
//......
}


} , {

})
)

매번 통신을 할때마다 httpCode를 가져와서 분기로 처리하고..... 매우 귀찮았다.

실제로 저 코드를 이용해서 무언가 세세하게 처리를 해야하는 로직이라면 상관없겠지만 , 내 회사 프로젝트의 경우 에러가 발생하면 토스트나 다이얼로그를 띄워주는것이 대부분이였다.



그래서 허접하지만 확장함수를 만들어서 작업을 해보았다.

fun <T> Single<Response<T>>.httpCodeSubscribe(success: (T) -> Unit, fail: (t: Throwable) -> Unit): Disposable =
map {
val httpCode = it.code()
if (it.isSuccessful) {

when (httpCode) {
200 -> {
it.body()!!
}
300 -> {
null
}
404 -> {
null
}
else -> {
null
}
}

//....
//.....

} else {
null
}
}.subscribe({
it?.let {
success.invoke(it)
}

}, {
fail.invoke(it)
})

확장함수안에서 httpCode를 받고 상황에 따라 토스트를 띄우든, 다이얼로그를 띄우든 변경했다.


한가지 마음에 안드는건 map {} 에서 네트워크 코드가 에러일 경우 null을 리턴하도록 했다. 이건 flatMap{} 으로 해도 마찬가지

암튼 이렇게 되니 throwable 에 nullPointExection 이 잡히긴 하는데 일단 정상적으로 통신하면 문제없고

에러가 나도 throwable로 빠지니 일단 상관없어 보인다.

아직까지 내가 이걸로 네트워크 통신했을 경우 문제되는 상황은 없었다.


더 좋은 방법이 있다면 알려주시면 감사하겠습니다.

제가 가진 지식으로는 이렇게 처리할 수 밖에 없었네요....




이제 확장함수로 다시 네트워크 통신을 진행하니 이런 모습이 나왔다.

compositeDisposable.add(
loginUseCase.phoneSignIn(apiBodyMap)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe { }
.doOnError { }
.doOnSuccess { }
.httpCodeSubscribe({
val loginData = it.results
//....
//.....

} , {

})
)


기존 subscribe을 쓰는것처럼 그대로 사용할 수 있다.

덕분에 api 호출단에선 httpCode 나 통신여부에 상관없이 데이터만 받아서 처리하면 된다.




* 참고로 나는 네트워크 통신시 불필요하거나 계속해서 중복이 되는 부분은 모두 확장함수로 대체했다.

이런식으로....

fun <T> Single<T>.defaultScheduler(): Single<T> = subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
fun <T> Single<T>.defaultDoOn(context: Context?): Single<T> =
doOnSubscribe {
context?.let {
progressBarDialog = ProgressBarDialog(it)
progressBarDialog?.show()
}
}.doOnSuccess {
progressBarDialog?.let {
it.dismiss()
progressBarDialog = null
}
}.doOnError {
progressBarDialog?.let {
it.dismiss()
progressBarDialog = null
}
}

 defaultDoOn() 에 context를 받은건 네트워크 통신시 로딩중인 다이얼로그를 띄워주려고 받았다.

이건 본인이 짜기 나름이다.



암튼 이렇게 모두 확장함수로 대체하니 네트워크 통신 코드가 확실히 간결해져서 난 매우 만족하며 사용하고 있다.

아래는 모두다 확장함수로 만들고 나서 실제로 내가 사용하는 코드다.

compositeDisposable.add(
loginUseCase.phoneSignIn(apiBodyMap)
.defaultScheduler()
.defaultDoOn(this)
.httpSubscribe(this , {
val loginData = it.results
//....
//....
} , {

})
)


반응형
Comments