스팀 앱 개발기 #91 - 태그 화면이 포스트 리스트 로딩 중에 다른 탭 클릭하면 앱이 죽는 문제 (1) 오류 내용, 원인
시작하며...
태그 화면 로딩 중에 다른 탭을 클릭하면, 앱이 강제종료 됩니다. 이유 무엇인지 알아보도록 하겠습니다.
오류 메시지
앱 종료시 발생한 예외는 NullPointerException이었습니다. 보다 자세한 내용을 보겠습니다.
오류 발생 위치
먼저 BaseFragment.kt:22로 가봅니다.
abstract class BaseFragment<VDB: ViewDataBinding, VM: BaseViewModel>(
@LayoutRes private val layoutResID: Int
) : Fragment() {
private var _binding: VDB? = null
protected val binding get() = _binding!! // 22번째 줄!
…
binding 필드는 null일 수 없는데, 이 값이 null로 되어 NullPointerException이 발생된 것으로 보입니다.
그 다음에 TagsFragment.kt:23으로 가보겠습니다. 이 라인은 TagsFragment 클래스 이름이 선언된 곳입니다. 오류의 직접적인 원인은 아니구요. 이 클래스 어딘가에서 오류가 발생한 것으로 파악됩니다. 그 다음 TagsFragment.kt:89로 가보겠습니다.
private fun readRankedPosts() {
val tag = activityViewModel.currentTag.value ?: ""
val sort = viewModel.sort.value ?: ""
if (sort.isEmpty()) {
showToastShortly(getString(R.string.error_sort_is_not_set))
return
}
binding.swipeRefreshPostList.isRefreshing = true
viewModel.readRankedPosts(
tag
) {
binding.swipeRefreshPostList.isRefreshing = false // 89번째 줄
}
}
89번째 줄에서 binding 객체 접근을 시도했으나 그것이 null이므로 NullPointerException이 발생했음을 알 수 있습니다.
원인
다른 탭을 클릭하여 태그 화면 담당 TagsFragment는 종료하기 위해 onDestroyView() 메소드가 호출 되었지만, 이 프래그먼트가 시작한 API는 여전히 실행되기 때문입니다. API로부터 포스트 리스트를 받은 후, 프래그먼트는 뷰를 갱신하기 위해 binding 객체에 접근하지만, 그것은 이미 null입니다. 없는 바인딩 객체에 접근하기 때문에 NullPointerException이 발생한 것입니다.
BaseFragment 클래스의 binding 필드는 null 값이 아님을 가정합니다. 그런데 본래 바인딩 객체 필드는 _binding이며 이것은 nullable(null 값을 가질 수 있음)입니다.
추가로 아래의 메시지도 받았습니다. 오류 해결에 도움이 될 것으로 보여 추가로 남겨봅니다.
해결 방법은?
다른 탭을 클릭하여 TagsFragment가 종료될 때, 실행 중인 API를 종료시켜야 합니다. 방법이 여러가지가 있는데, 가장 좋다고 판단되는 것을 택하여 내일 포스트를 이어가겠습니다.
마치며…
이번에도 버그 수정을 위한 포스트가 되었네요. 그만큼 개발이라는 직업 또한 쉬운 일이 아니라는 것을 개인 프로젝트를 통해서도 경험할 수 있습니다. 안정성이 높은 앱을 만들기 위해서는 많은 경험과 숙련된 기술이 필요합니다.
지난 스팀 앱 개발기
- #90 - 태그 화면에서 이미지가 뭉개지는 문제
- #89 - 태그 화면에서 다운보팅 카운트 클릭하면 앱이 죽는 문제
- #88 - 보팅 리스트 화면에 스팀잇 계정 검색 기능 추가
- #87 - 보팅 리스트 화면 개선: (1) 다운보팅도 보여주기 (2) 계정 썸네일 로딩 속도 개선
- #86 - 보팅 리스트 관련 데이터 클래스 보완
- #85 - 보팅 리스트 화면 구현
- #84 - 보팅 리스트 화면 구현을 위한 데이터 클래스 추가/변경
- #83 - 포스트의 보팅 리스트에서 각 보팅의 가치 계산 방법 정리
- #82 - 포스트의 보팅 리스트에서 각 보팅의 가치는 어떻게 계산해야 하나?
- #81 - 보팅 리스트 화면 개발 예정
- #80 - 버그 수정: 태그 화면 시작시 bridge.get_ranked_posts API가 여러 번 실행되는 문제
- #79 - 태그 화면에 새로 고침 기능 추가
- #78 - 태그 화면에서 포스트들의 디폴트 썸네일 변경
- #77 - 태그 화면에서 썸네일 없는 포스트 항목에 엉뚱한 썸네일이 보이는 오류
- #76 - 태그 검색시 앱이 죽는 버그 수정
- #75 - 태그 화면의 포스트 항목에 태그/커뮤니티 표시
- #74 - 태그 화면에서 포스트 리스트 추가 로딩시 깜빡임 문제 해결
- #73 - 태그 화면의 포스트 리스트에 무한 스크롤 적용
- #72 - 태그 화면의 포스트 리스트에서 항목들 사이 분리선 보이기
- #71 - 태그 화면에서 포스트 항목들의 썸네일 로딩
- #70 - 태그 화면 1차 구현
- #69 - 태그 화면에 데이터 바인딩 적용
- #68 - 태그 화면(TagsFragment) 구성
- #67 - TagsViewModel 클래스에 포스트 리스트 구하는 메소드 그리고 라이브 데이터 추가
- #66 - bridge.get_ranked_posts API 연동 구현: ReadRankedPostsUseCase 클래스 추가
- #65 - bridge.get_ranked_posts API 연동 구현: SteemRepository 인터페이스, SteemRepositoryImpl 클래스 수정
- #64 - bridge.get_ranked_posts API 연동 구현: SteemService 인터페이스에 메소드 추가
- #63 - bridge.get_ranked_posts API 관련 데이터 클래스 추가 수정
- #62 - bridge.get_ranked_posts API의 응답 자료를 맡을 데이터 클래스 수정
- #61 - layout_post_item.xml 수정 후 예상치 못한 빌드 오류
- #60 - bridge.get_ranked_posts API의 응답 자료를 맡을 데이터 클래스 정의
- #59 - 태그별 포스트 리스트를 구하기 위한 bridge.get_ranked_posts API
- #58 - 포스트 리스트를 구성할 항목의 레이아웃 (3) 데이터 클래스 정의 및 데이터 바인딩 적용
- #57 - 포스트 리스트를 구성할 항목의 레이아웃 (2)
- #56 - 포스트 리스트를 구성할 항목의 레이아웃
- #55 - .gitignore 파일 작성
- #54 - RxJava 관련 메모리 누수 방지 코드 작성
- #53 - 버그 수정: 인터넷 미연결시 API 실행하면 앱 강제 종료
- #52 - 인터넷 미연결시 API 실행하면 어떻게 될까?
- #51 - 파워다운 끝났으나 SP to power down 값이 0이 아닌 버그
- #1 ~ #50
Posted through the AVLE Dapp (https://avle.io)
[광고] STEEM 개발자 커뮤니티에 참여 하시면, 다양한 혜택을 받을 수 있습니다.
Upvoted! Thank you for supporting witness @jswit.