Upgrade to Pro — share decks privately, control downloads, hide ads and more …

DroidKnights 2025 - 다양한 스크롤 뷰에서의 영상 재생

DroidKnights 2025 - 다양한 스크롤 뷰에서의 영상 재생

Avatar for 이가은

이가은

June 16, 2025
Tweet

More Decks by 이가은

Other Decks in Programming

Transcript

  1. 􀇾 문제 발생 • 영상 잔상 이슈 • 스크롤 버벅임

    • OOM(Out Of Memory)로 인한 앱 다운 • 화면을 벗어나도 영상이 재생됨
  2. 목차 􀀻 렌더링 방법 선택하기 􀀽 영상 스크롤 뷰에 적용할

    수 있는 디자인 패턴 파헤치기 􀀿 스크롤 상황에 맞춰 영상 재생/중단하기
  3. 􀀻 렌더링 방법 선택하기 Android UI 렌더링 프로세스 Measure &

    Layout Draw Bu ff er Display Surface Double Bu ff ering
  4. SurfaceView • View 계층 구조 안에 별도의 Composite Layer를 삽입할

    수 있도록 해주는 컴포넌트 • UI 스레드가 아닌 별도의 Surface에서 렌더링하며, SurfaceFlinger가 하드웨어 오버레이로 별도의 레이어를 합성 • 카메라, 영상과 같은 외부 버퍼 소스를 렌더링할 때 사용 􀀻 ۪؊݂ ߑߨ ࢶఖೞӝ
  5. TextureView 􀀻 렌더링 방법 선택하기 • View와 SurfaceTexture를 결합한 뷰

    객체 • 뷰 계층에 직접 GPU 합성해 UI를 렌더링하는 컴포넌트 • SurfaceView와는 달리, TextureView는 별도의 레이어를 생성하지 않고 일반 뷰처럼 동작 􀰕 반투명, 회전 등의 후처리 작업 가능
  6. TextureView 􀃋 TextureView 􀆊 ղࠗীࢲ SurfaceTexture ࠁਬ 􀃍 onFrameAvailable callback

    􀆊 ࢜ ߡಌ ঌܿ 􀃏 TextureView invalidate 􀆊 ࠭ ޖബച ਃ୒ 􀘚 Copy buffer to view Canvas 􀆊 ਗࠄ Surface੄ ௑బஎ ࠂࢎ 􀃓 Display 􀆊 ചݶী ۪؊݂ 􀀻 ۪؊݂ ߑߨ ࢶఖೞӝ SurfaceTexture onFrameAvailable callback Copy buffer to view Canvas Display Wrapped by TextureView TextureView invalidate
  7. SurfaceView? TextureView? • 렌더링 레이턴시가 중요한 경우 • HDR 영상을

    다룰 때 • 일반적으로 TextureView 대신 SurfaceView를 사용하는 것을 권장 SurfaceView TextureView • 그래픽 후처리가 필요한 경우 • 다른 뷰와 겹쳐서 사용해야하는 경우 • 내부의 외부 그래픽 Surface contents 를 View로 복사해야하기 때문에 성능이 느려질 수 있음 􀀻 ۪؊݂ ߑߨ ࢶఖೞӝ
  8. TextureView 사용 예시 Android 14 이전 Android 14 이후 Composer

    HAL 3.2 ӝמ੉ ੸ਊغয, producer৬ consumer੄ োѾ੉ Րӝח ࣽр ೧׼ ۨ੉য੄ ߡಌ நदܳ ੗زਵ۽ purge GraphicBufferProducerо SurfaceFlinger੄ GraphicBufferConsumer৬ োѾ੉ ೧ઁغযب ߡಌ நदо ੗زਵ۽ ૑ਕ૑૑ ঋ਺
 􀰕 ੉੹ ೐ۨ੐ ߡಌо ݫݽܻী թই ੓যࢲ, ਖ਼࢚ അ࢚ ߊࢤ 􀀻 ۪؊݂ ߑߨ ࢶఖೞӝ
  9. 􀄣 Why 디자인패턴? Jetpack media 3 에서 UI 재생, Media

    Session 등 다양한 기능을 제공 But, 네트워크나 메모리 관리 등의 부분은 개발자가 직접 해야해야하는 숙제로 남아있음 􀀽 ٣੗ੋ ಁఢ ౵೻஖ӝ
  10. 􀂕 메모리 & 인스턴스 관리 • OOM(Out Of Memory)로 인한

    앱 다운 • 과도한 메모리 사용으로 스크롤 버벅임 􀀽 ٣੗ੋ ಁఢ ౵೻஖ӝ 문제 상황
  11. 􀂕 메모리 & 인스턴스 관리 • 클래스에 인스턴스가 하나만 있도록

    하면서 이 인스턴스에 대한 전역 접근 지점을 제공하는 생성 디자인 패턴 • ExoPlayer나 영상 캐시 관리처럼 어플리케이션 전역에서 하나의 인스턴스로 관리할 때 사용 가능 􀀽 ٣੗ੋ ಁఢ ౵೻஖ӝ 싱글톤 패턴(Singleton Pattern) 􁷘 উ٘۽੉٘ hilt ۄ੉࠳۞ܻܳ ੉ਊ೧ ё୓੄ scopeܳ यӖహਵ۽ ࢸ੿೧ࢲ ੋझఢझܳ ҙܻೡ ࣻب ੓णפ׮.
  12. 􀂕 메모리 & 인스턴스 관리 􀀽 ٣੗ੋ ಁఢ ౵೻஖ӝ 객체

    풀 패턴(Object Pool Pattern) • 재사용 가능한 객체를 Pool에서 관리함으로써 객체의 생성 및 소멸에 따른 오버헤드를 최소화하는 패턴
  13. 􀄵 코드로 적용하기 MAX_VIDEO_COUNT • ё୓੄ ୭؀ Pool੄ ௼ӝ •

    ٣੗ੋҗ ۽૒ ࢚ടী ٮۄ ੗ਬ܂ѱ ࢸ੿ 􀀽 ٣੗ੋ ಁఢ ౵೻஖ӝ
  14. 􀄵 코드로 적용하기 LinkedHashMap • о੢ য়ېػ ExoPlayer ё୓ܳ ଺ই

    ࢏ઁ • Poolਸ ੉ਊ೧ ExoPlayer ё୓ ҙܻ 􀀽 ٣੗ੋ ಁఢ ౵೻஖ӝ
  15. 􀂗 캐싱 관리 􀀽 ٣੗ੋ ಁఢ ౵೻஖ӝ • 향후 데이터

    요청을 더 빠르게 처리할 수 있도록 데이터를 저장하는 기법 • 빠르게 영상을 로드할 수 있기 때문에 사용자 경험을 한층 개선할 수 있음 캐싱이란?
  16. 􀂗 캐싱 관리 􀀽 ٣੗ੋ ಁఢ ౵೻஖ӝ • 특정 상황에서

    대비하여 캐싱 로직을 최적화해야함 • 예시: 유저 자신이 업로드한 영상만 선택적으로 미리 캐싱 문제 상황
  17. 􀂗 캐싱 관리 프록시 패턴(Proxy Pattern) • 영상을 네트워크로부터 직접

    로드하기 전에 프록시 객체가 요청을 먼저 가로채 캐시된 영상이 있는지 확인 • 캐시에 영상이 존재하면 네트워크 호출 없이 캐시된 데이터를 반환하고, 없다면 네트워크에서 영상을 로드 􀀽 ٣੗ੋ ಁఢ ౵೻஖ӝ
  18. 􀂗 캐싱 관리 2. ٣੗ੋ ಁఢ ౵೻஖ӝ 􀀽 ٣੗ੋ ಁఢ

    ౵೻஖ӝ • 영상을 로컬 파일 시스템에 저장하고 요청 시 캐시에서 먼저 데이터를 조회 • 캐시에 데이터가 없으면 파일이나 네트워크에서 영상을 로드한 후 캐시에 저장하여, 다음 요청부터는 캐시에서 빠르게 로드 캐시 어사이드 패턴(Cache-Aside Pattern)
  19. 􀂗 캐싱 관리 2. ٣੗ੋ ಁఢ ౵೻஖ӝ 􀀽 ٣੗ੋ ಁఢ

    ౵೻஖ӝ • 파일 시스템에서 영상 데이터를 관리할 때도 싱글톤 패턴이 자주 활용 • 하나의 파일 관리 인스턴스를 통해 모든 파일 접근을 효율적으로 관리 • 파일 입출력 과정에서 발생할 수 있는 중복 접근과 성능 저하를 방지 싱글톤 패턴(Singleton Pattern)
  20. 􀄵 코드로 적용하기 􀕻 ೐۾द ಁఢҗח ׳ܻ, நद যࢎ੉٘ ಁఢীࢲח

    য೒ܻா੉࣌੉ ݺद੸ਵ۽ ؘ੉ఠܳ நदী ੷੢ೡ ࣻ ੓णפ׮.
  21. 􀄵 코드로 적용하기 􀕻 ೐۾द ಁఢҗח ׳ܻ, நद যࢎ੉٘ ಁఢীࢲח

    য೒ܻா੉࣌੉ ݺद੸ਵ۽ ؘ੉ఠܳ நदী ੷੢ೡ ࣻ ੓णפ׮.
  22. 􀀽 ٣੗ੋ ಁఢ ౵೻஖ӝ • Player의 상태에 따른 분기처리가 너무

    많아서 관리하기 힘든 경우가 다수 문제 상황 􀂙 재생 상태 관리
  23. 􀂙 재생 상태 관리 상태 패턴(State Pattern) 􀀽 ٣੗ੋ ಁఢ

    ౵೻஖ӝ • ExoPlayer 객체의 상태(재생, 일시정지, 로딩 중, 오류 상태 등)를 각각 별도의 객체로 관리하는 방식 • 상태 전환과 각 상태에 따른 동작을 체계적으로 정의하여 코드 복잡성을 줄이고 유지보수와 확장성을 높일 수 있음
  24. 􀂛 영상 설정 관리 􀀽 ٣੗ੋ ಁఢ ౵೻஖ӝ • Player에

    새로운 기능을 동적으로 추가해야하는 경우 • 객체에 직접적으로 기능을 추가할 경우, 로직을 재사용하거나 조합하기 어려움 • 예시: 자막, 반복 재생, 음소거, 필터 문제 상황
  25. 􀂛 영상 설정 관리 􀀽 ٣੗ੋ ಁఢ ౵೻஖ӝ • 객체에

    추가 기능을 동적으로 넣을 수 있도록 하는 구조적 패턴 • 기본 영상 플레이어 객체를 변경하지 않고도 새로운 기능을 쉽게 추가하거나 제거할 수 있어 확장성이 좋음 데코레이터 패턴(Decorator Pattern)
  26. 다양한 스크롤 상황 • LazyColumn • Recyclerview • HorizontalPager •

    디바이스 화면을 넘어가는 Composable 􀰕 화면을 벗어나면 영상이 중단되어야함 􀰕 여러 영상들이 있을 경우, 하나만 재생되어야함 􀀿 झ௼܀ ࢚ടী ݏ୶য ৔࢚ ੤ࢤ/઺ױೞӝ
  27. 􀂕 LazyColumn 􀀿 झ௼܀ ࢚ടী ݏ୶য ৔࢚ ੤ࢤ/઺ױೞӝ • LazyColumn의

    경우 LazyListState 를 관찰하여 현재 보이는 리스트 아이템의 LazyListItemInfo 를 가져올 수 있음 • 해당 정보를 이용해, 리스트에서 어떤 index의 video를 재생할지 결정
  28. 􀂕 LazyColumn 3. झ௼܀ ࢚ടী ݏ୾ ৔࢚ ੤ࢤ/઺ױೞӝ 예시: 현재

    화면에 보이는 아이템의 개수가 최대 3개일 때 • 현재 보이는 아이템의 개수가 1개인 경우 → 첫 번째 index의 video를 재생 • 현재 보이는 아이템의 개수가 2개인 경우 → height의 70%가 보여지는 아이템 중에서, 첫 번째 요소를 재생 • 현재 보이는 아이템의 개수가 3개인 경우 → 가운데 video를 재생 􀀿 झ௼܀ ࢚ടী ݏ୶য ৔࢚ ੤ࢤ/઺ױೞӝ
  29. 􀂗 Recyclerview의 경우 • fi ndFirstVisibleItemPosition() / fi ndLastVisibleItemPosition() 으로

    현재 화면에 붙어 있는 어댑터 포지션 범위를 구함 • 해당 정보를 이용해, 리스트에서 어떤 index의 video를 재생할지 결정 􀀿 झ௼܀ ࢚ടী ݏ୶য ৔࢚ ੤ࢤ/઺ױೞӝ
  30. 􀂙 HorizontalPager의 경우 • currentPage 를 관찰하여 페이지가 변경될 때

    로직 수행 • 현재 페이지를 제외한 다른 페이지의 영상은 중단 􀀿 झ௼܀ ࢚ടী ݏ୶য ৔࢚ ੤ࢤ/઺ױೞӝ
  31. 􀂛 디바이스 화면을 넘어가는 Composable 3. झ௼܀ ࢚ടী ݏ୾ ৔࢚

    ੤ࢤ/઺ױೞӝ 디바이스 화면을 넘어가는 Composable 내부에 특정 컴포넌트만 Video일 경우, 스크롤을 함 에 따라 영상 재생이 중단되어야 합니다. 이 경우, 현재 컴포넌트가 화면에 보이는지 여부를 판단하여 영상 재생 로직을 구현해야 합니다. 􀀿 झ௼܀ ࢚ടী ݏ୶য ৔࢚ ੤ࢤ/઺ױೞӝ
  32. 􀀿 झ௼܀ ࢚ടী ݏ୶য ৔࢚ ੤ࢤ/઺ױೞӝ 􀄵 코드로 적용하기 onGloballyPositioned

    ஹನ੷࠶੉ पઁ۽ ۨ੉ইਓী ߓ஖ػ റ੄ ਤ஖ ੿ࠁ (LayoutCoordinates)ܳ ઁҕ೧઱ח ௒ߔ
  33. 마치며 • 기초부터 시작해서 점차적으로 해결하는 것이 중요 • 정답은

    없으며 각 상황에 맞춰 적절한 해결 수단을 찾아야함 • 개발적 제한 요소에 따라 적용할 수 있는 방법들이 달라질 수 있음
  34. • Google I/O - Drawn out: How Android renders •

    Android 공식 문서 - Surface and SurfaceHolder 참고 자료 • Android 공식 문서 - Reduce graphic memory consumption • Refactoring Guru