[Android] Fatal Exception: java.lang.IllegalStateExceptionObject is no longer valid to operate on. Was it deleted by another thread? Realm DB 관련 오류 대응

2025. 3. 19. 10:09· Development/Android
반응형

- 자사 서비스에서 Realm DB를 활용하고 있다.

 

- Realm DB는 빠르고 가벼운 로컬 데이터 저장을 위한 객체 기반 데이터베이스이다. 

 

- Realm DB의 객체로 리스트를 구성할 때는 RealmRecyclerViewAdapter를 이용하여 구성할 수 있다.

 

- 내부 구성은 일반 RecyclerView와 크게 다르지 않다. 하지만 getItem 등의 함수가 RealmDB 자체에서 오리지널 인스턴스를 가져오는 방식으로 동작한다.

/**
 * Returns the item in the underlying data associated with the specified position.
 *
 * This method will return {@code null} if the Realm instance has been closed or the index
 * is outside the range of valid adapter data (which e.g. can happen if {@link #getItemCount()}
 * is modified to account for header or footer views.
 *
 * Also, this method does not take into account any header views. If these are present, modify
 * the {@code index} parameter accordingly first.
 *
 * @param index index of the item in the original collection backing this adapter.
 * @return the item at the specified position or {@code null} if the position does not exists or
 * the adapter data are no longer valid.
 */
@SuppressWarnings("WeakerAccess")
@Nullable
public T getItem(int index) {
    if (index < 0) {
        throw new IllegalArgumentException("Only indexes >= 0 are allowed. Input was: " + index);
    }

    // To avoid exception, return null if there are some extra positions that the
    // child adapter is adding in getItemCount (e.g: to display footer view in recycler view)
    if(adapterData != null && index >= adapterData.size()) return null;
    //noinspection ConstantConditions
    return isDataValid() ? adapterData.get(index) : null;
}

 

- 서비스에서는 스와이프 동작을 하면 지정한 아이템이 물리적으로 삭제되고, 서버에서 푸시가 내려오면 observer 패턴으로 자동 갱신이 되는데 삭제 이후 곧바로 새로운 푸시가 수신되는 상황에서 아주 드물게 중첩 상황으로 인한 오류가 발생하는 것으로 보인다.

 

- 정확히는 삭제 이후 서버 푸시로 인한 자동 갱신에서 리스트에는 아직 삭제가 반영되지 않은 오리지널 인스턴스가 살아있어 유효성에 대한 Exception을 발생시키는 것으로 확인된다.

 

- 대응 방법 첫 번째 단계로 먼저 isValid라는 RealmDB에서 해당 인스턴스의 유효성을 검사하는 Boolean 함수를 사용해준다.

override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val noti = getItem(position) ?: return
if (noti.isValid) {
} else {
    notifyDataSetChanged()
}

- 유효하지 않다면 다시 Adapter의 갱신을 진행한다.

 

- 대응 방법 두 번째 단계로 onBindViewHolder에서 삭제 처리를 고려하여 안전성을 위해 copyFromRealm()을 사용한다.

val realm = Realm.getDefaultInstance()
val noti = getItem(position) ?: return
if (noti.isValid) {
    val notification = realm.copyFromRealm(noti)

- 해당 메서드는 Realm DB로부터 독립적인 복사 객체를 전달하므로 원본에 비해 유효성에 대한 위험성이 없다.

 

- 만일 삭제 시나리오가 없는 단순 UI 표시 로직에서는 굳이 이 메서드를 사용할 필요는 없다.

반응형
저작자표시 (새창열림)
'Development/Android' 카테고리의 다른 글
  • [Android] 자정이 지나면 위젯 갱신하기 (feat. BroadcastReceiver)
  • [Android] Gradient 테두리를 가진 커스텀 버튼 View 구현 (XML)
  • [Android] 구글 인앱 결제 처리 관련 코드를 Manager로 정리
  • [Android] Compose + Coroutine(API 호출) 간단하게 페이징 처리 구현하기
SeungYong.Lee
SeungYong.Lee
반응형
SeungYong.Lee
Win-Dev
SeungYong.Lee
전체
오늘
어제
  • All (241)
    • Development (141)
      • Android (137)
      • iOS (0)
      • Flutter (4)
      • Backend (0)
    • Algorithm (5)
    • Knowledge (5)
      • IT (2)
      • Science (0)
      • ETC & Tip (3)
    • Today I Learn (28)
    • Coding Test (62)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

  • 안녕하세요. 반갑습니다 :)

인기 글

태그

  • 프로그래머스
  • Retrofit
  • 코딩테스트
  • Java
  • 비동기처리
  • glance
  • exception
  • Animation
  • Android
  • HTTP
  • Kotlin
  • compose
  • Collection
  • bitmap
  • Flutter
  • hilt
  • 코틀린
  • Widget
  • dfs
  • coroutine

최근 댓글

최근 글

hELLO · Designed By 정상우.v4.2.2
SeungYong.Lee
[Android] Fatal Exception: java.lang.IllegalStateExceptionObject is no longer valid to operate on. Was it deleted by another thread? Realm DB 관련 오류 대응
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.