2017년 10월 23일 월요일

Conductor 소스 분석


Conductor
  • MainActivity: 최상단 activity
    • Conductor.attachRouter를 통해 Activity와 Activity 안의 container(FrameLayout으로 만든다.)와 savedInstanceState를 연결하는 Router를 만든다.
    • attachRouter: LifecycleHandler라는 Fragment를 만들어서 Activity에 연결한다. 실제 Router는 LifecycleHandler에서 만든다.
  • Router: stack을 통해 Controller의 go/back을 관리한다.
    • Router의 setRoot를 통해 최상단에 적용할 Controller를 연결한다. Controller는 RouterTransaction을 통해 Router에 연결된다.
  • Controller: inflateView를 통해 View를 연결한다.
  • ControllerChangeHandler: View의 변환시 Animation이나 Transition을 한다.

LifecycleHandler

  • Fragment를 상속한다.
  • setRetainInstance(true)를 통해 activity가 recreate될 때 fragment도 같이 recreate되지 않도록 한다.
  • activeLifecycleHandlers를 통해 activity마다 하나의 LifecycleHandler를 연결한다.
  • application에 자신을 ActivityLifecycleCallbacks으로 등록한다.
  • pendingPermissionRequests: 퍼미션 요청하는 것에 대한 관리
  • routerMap을 통해 container(ViewGroup)마다 하나의 ActivityHostedRouter를 연결한다.

Router

  • ActivityHostedRouter and ControllerHostedRouter
  • ActivityHostedRouter는 LifecycleHandler와 연결하고, ControllerHostedRouter는 Controller와 연결한다.
  • InstanceState를 써서 data를 유지한다: KEY_BACKSTACK, KEY_POPS_LAST_VIEW
  • setRoot를 통해 최상단 RouterTransaction을 연결한다.
    • BackStack에 RouterTransaction을 넣는다.
    • ControllerChangeHandler.executeChange를 통해 RouterTransaction의 Controller에 연결되어 있는 View를 addView한다. 이전것은 removeView한다.
    • add와 remove를 위해 ControllerChangeHandler를 사용한다. RouterTransaction에 연결된 ControllerChangeHandler가 없으면 애니메이션없는 SimpleSwapChangeHandler를 사용한다.
  • Backstack
    • ArrayDeque을 통해 백스택 구현
    • Iterator<RouterTransaction> 및 reverseIterator 제공
  • Backstack에 controller가 들어가면 아래의 라이프 관련 함수가 호출된다.
    • onContextAvailable
    • inflate
  • Backstack에서 controller가 빠지면 아래의 라이프 관련 함수가 호출된다.
    • detach
    • destroy

ControllerChangeHandler

  • Controller로부터 View를 얻어온다: inflate
  • performChange를 통해 View의 push/pop을 실행한다.
  • AnimatorChangeHandler
    • performChange 함수에서 addView를 하고 animation을 시작한다.
    • animation은 subclass의 getAnimator를 통해 얻어온다.
    • FadeChangeHandler: AnimatorChangeHandler를 상속하여 getAnimator와 resetFromView를 구현
      • getAnimator: AnimatorSet를 사용하여 기존의 뷰는 알파를 0으로, 새로운 뷰는 알파를 0에서 1로 변경한다.
      • resetFromView: 애니메이션이 끝나면 호출되는 함수. 기존의 뷰의 알파를 1로 바꾼다.

Controller

  • instanceId: UUID.randomUUID().toString()
  • 화면의 구성을 위해 inflate가 호출된다.
    • onCreateView를 호출하여 View를 생성한다.
    • subclass에서 inflateView와 onViewBound를 구현한다.
  • detach시 onSaveViewState를, inflate시 onRestoreViewState를 호출해준다.

RouterTransaction

  • Controller와 (pushChangeHandler, popChangeHandler)의 연결고리를 Router에 제공한다.

Lifecycle 관리

  • LifecycleHandler는 ActivityLifecycleCallbacks를 구현한다.
    • ActivityLifecycleCallbacks는 Application에 선언되어 있는 인터페이스이다.
    • 콜백이 불리면 Router의 Lifecycle 관련 함수를 호출한다.
  • Router는 Lifecycle 관련 함수를 정의하고 있다.
    • 이 함수에서는 Controller의 Lifecycle 관련 함수를 호출한다.
    • child router가 있으면 이의 Lifecycle 관련 함수를 호출한다.
  • LifecycleListener
    • Controller에 등록해서 Lifecycle 이벤트를 받는다.

AutoDispose

  • ControllerScopeProvider
    • Controller에서 라이프 사이클이 바뀌면 BehaviorSubject를 통해 이벤트가 발생하도록 한다.
    • lifecycle에서 아이덴티티를 숨긴 lifecycleSubject.hide()를 리턴한다.
    • correspondingEvents에서 dispose를 하기 위해 대응되는 매핑(CORRESPONDING_EVENTS)을 리턴한다.
    • peekLifecycle에서 BehaviorSubject의 현재 값을 리턴한다.

Building asynchronous views in SwiftUI 정리

Handling loading states within SwiftUI views self loading views View model 사용하기 Combine을 사용한 AnyPublisher Making SwiftUI views refreshable r...