1. 나의 해결법
refreshRecyclerView (새로고침 기능)
endlessRecyclerView (목록의 끝에 도달하면 다음 항목 불러오는 기능)
이 두 개를 같이 사용하다가 문제가 생겼다.
새로고침을 한 다음에 스크롤을 빠르게 내리면 앱이 강제 종료가 되어버린다.
[Inconsistency detected. Invalid view holder adapter positionMyNoticeViewHolder{38334d0 position=8 id=-1, oldPos=-1, pLpos:-1 no parent]
IndexOutOfBoundsException이 떴고 position에 대해 이야기하는 걸 보니
새로고침을 하고 리스트를 로드하는 과정에서 문제가 있는 것 같았다.
실제로도 새로고침을 하지 않고 빠르게 스크롤을 해도 에러가 안뜨는데 꼭 새로고침 이후에만 문제가 생겼다.
아무튼 그래서 찾아낸 원인은
새로고침이 다 되기도 전에 스크롤을 내려서(아이템 항목을 불러와서)이다.
화면에는 이전 아이템 목록이 그대로 보이기 때문에 벌써 새로고침이 다 된 것처럼 보여서 인지하지 못했다.
refresh_layout.setOnRefreshListener(PullRefreshLayout.OnRefreshListener {
activity!!.window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) // 화면 터치 못하게 하기
notices.clear() // 항목 리셋
crawler.activateBot(page) // 새로운 항목 불러오기 (내가 만든 메서드)
val handler = android.os.Handler()
handler.postDelayed({
keywordAdapter!!.notifyDataSetChanged() // 새로고침
refresh_layout.setRefreshing(false) // 새로고침 아이콘 없애기
activity!!.window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) // 이제 터치가능
}, 1000) // 1초 딜레이
})
이 어이없는 에러가 발생한 이유는
내가 콜백메서드와 비동기 실행에 대한 이해가 부족해서 발생했다.
(어휴 그러니까 공부 좀 하지 ㅡㅡ)
우선 임시방편으로 새로고침할때 무조건 1초의 딜레이를 가지게 하고 사용자가 화면을 터치하지 못하도록 막았다.
실제로 걸리는 시간이 1초보다 짧으면 손해고 1초보다 길면 또 에러를 뱉어낼 것이므로.. 꼭 고쳐야 한다.
(2021.02.14 추가)
코루틴을 이용해서 문제를 해결하였다. 위 글 참고!
2. 다른 해결법(1)
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
var safePosition = holder.adapterPosition
title.text = notices[safePosition].title
}
나한테는 통하지 않은 방법이지만
저 에러가 뜨는 이유는 여러 가지일 테니 기록을 해두려고 한다.
방법은 간단하다. onBindViewHolder에서 매개변수로 넘어오는 position대신
holder.adapterPosition을 사용하는 것이다.
이 블로거분의 글을 참고했다. 이분은 이 방법으로 해결하셨다고 한다.
3. 다른 해결법(2)
class LinearLayoutManagerWrapper: LinearLayoutManager {
constructor(context: Context) : super(context) {}
constructor(context: Context, orientation: Int, reverseLayout: Boolean) : super(context, orientation, reverseLayout) {}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {}
override fun supportsPredictiveItemAnimations(): Boolean { return false }
}
이런 클래스를 생성하고
mRecyclerView.layoutManager = LinearLayoutManager(context) // 이거 대신
val linearLayoutManagerWrapepr = LinearLayoutManagerWrapper(context!!, LinearLayoutManager.VERTICAL, false) // 이걸 만들어서
mRecyclerView.layoutManager = linearLayoutManagerWrapper // 이걸 넣는다.
LinearLayoutManager 대신에 넣는 방법이다.
나는 이 방법을 쓰고 해결된 듯 보였으나(?)
다른 에러가 대신 떠서 포기했다.
이 블로거 분의 글을 참고했다.
4. 다른 해결법(3)
스크롤을 빠르게 내렸을 때
리스트의 최하단에 도달했는지 감지가 제대로 안되는 경우도 있는 것 같다.
위 게시글의 1-5, 1-6 부분을 참고해서 보완을 해보는 것도 좋을 것 같다.
'앱 제작 > 키워드 알림 앱' 카테고리의 다른 글
[학교 공지 알림 앱] 아냥이 프로젝트 최종 결과 (6) | 2021.02.06 |
---|---|
파이어베이스 보안규칙 가입 없이 설정하기 (익명 로그인) (5) | 2021.02.01 |
헤로쿠(heroku)에서 파이어베이스를 credentials JSON 파일 없이 사용하기 (1) | 2021.01.20 |
2주 동안의 프로젝트 결과 (2) | 2021.01.14 |
왕초보 개발자의 안드로이드 앱 UI 기본 공부하기 - 1편 (0) | 2021.01.13 |
댓글