스택큐힙리스트

이어보기 완성! Iterator + Memento로 구현한 플레이백 히스토리 본문

개발

이어보기 완성! Iterator + Memento로 구현한 플레이백 히스토리

스택큐힙리스트 2025. 7. 30. 16:20
반응형

동영상/오디오 앱에서 “지난번 보던 자리부터 이어보기” 는 필수 UX입니다.
이 기능은 사실 두 가지 디자인 패턴이 만나면 깔끔하게 풀립니다.

  • Memento – 플레이어의 ‘스냅샷’을 저장·복원해 재생 위치를 되살린다.
  • Iterator – 저장된 스냅샷 목록을 순회해 최근 기록을 탐색‧표시한다.

아래 예시는 조회수 높은 한국 안드로이드 블로그들의 패턴 사용법을 베이스로, 실제 서비스 코드 형태로 재구성했습니다.


1. 핵심 클래스 설계

  1. PlayerState (Memento)
    @JvmInline value class PlayerState(val positionMs: Long)

    • 불변(immutable)이라 복원 시 사이드이펙트 없음. 
  2. VideoPlayer (Originator)
    class VideoPlayer(private val exo: ExoPlayer) {
        fun save() = PlayerState(exo.currentPosition)
        fun restore(state: PlayerState) { exo.seekTo(state.positionMs) }
    }

PlayHistory (Caretaker + Iterable)

class PlayHistory : Iterable<PlayerState> {
    private val history = ArrayDeque<PlayerState>()  // 최신 → 오래된 순
    fun push(state: PlayerState) { history.addFirst(state) }            // 저장
    fun iterator() = history.iterator()             // Iterator 패턴
}

 


2. 저장·복원 흐름

val player   = VideoPlayer(exo)
val history  = PlayHistory()

// ► 사용자가 시청 중일 때 주기적으로 or onPause 시점 저장
lifecycle.addObserver(object : DefaultLifecycleObserver {
    override fun onPause(owner: LifecycleOwner) {
        history.push(player.save())
    }
})

// ▶ 앱 재실행 후 이어보기
for (state in history) {           // Iterator 순회
    // UI에 “10분 12초까지 봤어요”처럼 표시
    showResumeButton(state.positionMs)
}
resumeButton.setOnClickListener {
    player.restore(history.first()) // 가장 최근 상태 복원
}
  • Iterator 덕분에 for (state in history) 처럼 깔끔하게 순회합니다.
  • Memento 로 캡슐화가 유지돼 VideoPlayer 내부 구현을 외부가 모를 수 있습니다.

3. 실전 팁

  • 스냅샷 크기 최소화
    위치·속도·자막 언어 등 필요한 필드만 담아 메모리 낭비를 줄입니다.
  • 저장 빈도 전략
    • 배터리 절약을 위해 onPause, every 30 sec 와 같이 타임아웃을 두세요.
  • 보관 주기 관리
    ArrayDeque 용량을 제한하거나, 30일 이상 지난 항목은 Iterator 순회 전에 제거해서 DB‧SharedPref를 슬림하게 유지합니다.
  • 멀티 디바이스 싱크
    Caretaker가 Firebase/Hasura 같은 실시간 DB로 직렬화-업로드하면 어떤 기기에서도 즉시 이어볼 수 있습니다.
  • Unit Test
    Iterator는 단순 순서 보장만 확인하면 되므로 assertEquals(listOf(state3,state2,state1), history.toList()) 정도면 충분합니다.

4. 한 줄 정리

Iterator로 “히스토리를 탐색”하고, Memento로 “시간을 복원”하면 이어보기 UX가 자연스레 완성된다.

반응형
Comments