스팀 앱 개발기 #53 - 버그 수정: 인터넷 미연결시 API 실행하면 앱 강제 종료
시작하며...
오늘은 어제 말씀드린 인터넷 미연결시 API를 실행하면 앱이 죽는다고 말씀드렸지요. 오늘은 이 문제를 해결하는 과정을 보여드리고자 합니다.
스크린샷
인터넷 연결을 끊고, 지갑 화면에서 계정을 입력합니다. 그러면 앱이 죽는 문제가 해결이 되었고요. 아래 그림과 같이 "Error. Check internet connection." 토스트가 화면에 뜹니다.
작업 개요
확장함수 추가: Fragment 클래스의 showToastShortly(msg)
예외 관찰 및 처리 구현
API 연동 중 예외 캐치
확장함수 추가: Fragment 클래스의 showToastShortly(msg)
API 실행 중 인터넷 미연결로 인해 UnknownHostException이 발생하지요. 이 때 토스트를 띄워 오류를 알리려고 합니다. Toast 클래스를 사용해도 되지만, 파라메터들이 여러개 있어 가독성이 떨어지죠. 이를 해결하기 위해 Fragment 클래스에 showToastShortly 확장 함수를 추가하였습니다.
fun Fragment.showToastShortly(msg: String) {
Toast.makeText(this.activity, msg, Toast.LENGTH_SHORT).show()
}
예외 관찰 및 처리 구현
프래그먼트들에 API 연동시 발생할 예외를 담을 라이브 데이터를 구현할 프래그먼트들의 뷰모델에 예외를 담을 라이브 데이터가 필요합니다. 뷰모델들에게 공통적으로 필요하므로 이들의 부모 뷰모델이 필요하다고 판단했습니다. 이에 BaseViewModel 클래스를 새로 추가했습니다.
open class BaseViewModel: ViewModel() {
// To handle exceptions from calling APIs
val liveThrowable = MutableLiveData<Throwable>()
}
BaseViewModel 클래스에서 정의한 liveThrowable의 관찰 및 처리는 BaseFragment 클래스 안에 구현했습니다. 작업 내용은 다음과 같습니다
BaseFragment 클래스의 VM 파라메터의 베이스 타입을 ViewModel에서 BaseViewModel로 변경
뷰모델의 liveThrowable 라이브 데이터를 관찰, 처리할 liveThrowableObserver 필드 정의
onViewCreated 메소드 추가하고 뷰모델의 liveThrowable 라이브 데이터 관찰 요청
abstract class BaseFragment<VDB: ViewDataBinding, VM: BaseViewModel>(
@LayoutRes private val layoutResID: Int
) : Fragment() {
// ...
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.liveThrowable.observe(viewLifecycleOwner, liveThrowableObserver)
}
// ....
protected val liveThrowableObserver = Observer<Throwable> { error ->
when (error) {
is UnknownHostException -> showToastShortly("Error. Check internet connection.")
}
}
}
추가로 뷰모델 클래스들의 부모 클래스는 ViewModel에서 BaseViewModel로 변경하였습니다.
API 연동 중 예외 캐치
WalletViewModel 클래스의 readSteemitWallet 메소드에서 오류 처리를 담당하려던 doOnError 메소드 호출을 onErrorReturn 메소드로 대체했습니다. 후자에서 liveThrowable 라이브 데이터의 value를 새로 설정하구요. 이를 관찰하는 BaseFragment 객체의 liveThrowableObserver가 이를 처리합니다.
class WalletViewModel : BaseViewModel() {
// ...
fun readSteemitWallet(account: String): Single<Array<SteemitWallet>> {
return readSteemitWalletUseCase(account)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.onErrorReturn { error ->
error.printStackTrace()
liveThrowable.value = error
arrayOf(SteemitWallet())
}
.doOnSuccess { steemitWallets ->
steemitWallet.value = when {
(steemitWallets.size > 0) -> steemitWallets[0]
else -> SteemitWallet()
}
}
}
}
GitHub Commit
지난 스팀 앱 개발기
- #52 - 인터넷 미연결시 API 실행하면 어떻게 될까?
- #51 - 파워다운 끝났으나 SP to power down 값이 0이 아닌 버그
- #50 - get_state API 쓸까? 말까?
- #49 - get_state API 시험해 보기
- #48 - 스팀 파워 값이 스팀잇 사이트와 다른 문제 분석
- #47 - 스팀 파워 값이 스팀잇 사이트와 다른 문제
- #46 - 다음 개발 아이템들
- #45 - 지갑 화면에서 다음 파워 다운 시간 보여주기
- #44 - 지갑 화면에 파워 다운 내용 보여주기
- #43 - 지갑 화면에서 VEST 값을 SP로 변환
- #42 - VEST를 SP로 변환하는 메소드
- #41 - 작성중...
- #40 - UTC 시간을 로컬 시간으로 바꾸는 코드 만들기
- #39 - condenser_api.get_dynamic_global_properties API 실행에 필요한 데이터 클래스 추가
- #38 - 지갑 화면 구현: 예금 보여주기 추가
- #37 - 지갑 화면 구현: WalletViewModel과 WalletFragment를 바인딩
- #36 - 유닛 테스트로 구현한 WalletViewModelTest 클래스에서 공통 부분 추출하여 CommonPartOfViewModelTest 클래스 만들기
- #35 - 유닛 테스트용 WalletViewModelTest 클래스 구현 후 보이는 문제점
- #34 - WalletViewModel 클래스에 스팀 지갑 정보 읽는 코드 작성
- #33 - 추가 리팩토링: 데이터 모듈의 데이터 클래스의 필드들에 nullable 적용
- #32 - 리팩토링: 데이터 클래스 이름 변경
- #31 - 도메인 모듈에서 정의하는 데이터 클래스들이 DTO 패턴을 따르는 것이 맞는가?
- #30 - 진도를 더 나가기 전에 리팩토링 고려 중
- #29 - 뷰모델, Repository 패턴 그리고 Use Case 패턴의 관계
- #28 - Use Case 패턴 적용
- #27 - Repository 패턴 적용
- #26 - condenser_api.get_accounts API로 받은 계정 자료를 SteemitWalletDTO 타입으로 변환하기
- #25 - SteemClient, SteemService 잘 작동하는지 유닛 테스트
- #24 - API 실행을 담당할 SteemService 인터페이스 정의
- #23 - condenser_api.get_accounts API 연동에 필요한 데이터 클래스 정의
- #22 - API 연동에 필요한 라이브러리 추가
- #21 - 사용자 지갑 정보를 담을 SteemitWallet 클래스 정의
- #20 - 클린 아키텍처를 위한 모듈 구성 (2)
- #19 - 클린 아키텍처를 위한 모듈 구성 (1)
- #18 - VEST로부터 STEEM POWER를 계산하는 방법
- #17 - VEST를 STEEM POWER로 변환하기 위해 필요한 get_dynamic_global_properties API
- #16 - 지갑 내용을 읽기 위해 필요한 API
- #15 - 지갑 서브화면(WalletFragment) 레이아웃 구성해 보기
- #14 - 지갑 서브화면(WalletFragment)에서 계정 인식하기
- #13 - 프로파일 서브화면(ProfileFragment)에서 계정 인식하기
- #12 - 태그 서브화면에서 태그 인식하기
- #11 - 검색 레이아웃을 메인 화면에 적용
- #10 - 태그 및 계정 검색 레이아웃 만들기
- #9 - BaseActivity 클래스 정의 그리고 MainActivity 클래스에 적용
- #8 - BaseFragment 클래스 정의 그리고 기존 프래그먼트들에 적용
- #7 - ProfileFragment 그리고 WalletFragment에 데이터 바인딩 적용
- #6 - 태그별 검색 내용을 보여줄 TagsFragment에 데이터 바인딩 적용
- #5 - GitHub에 소스 올리기
- #4 - 하단 내비게이션의 탭 관련 클래스 이름 수정
- #3 - 하단 내비게이션 바의 아이콘, 텍스트 수정
- #2 - 프로젝트 생성
- #1 - 시작하며...
Posted through the AVLE Dapp (https://avle.io)

[광고] STEEM 개발자 커뮤니티에 참여 하시면, 다양한 혜택을 받을 수 있습니다.
Upvoted! Thank you for supporting witness @jswit.