Android에서 Configuration change 혹은 Multiple screen size 대응 시 알면 좋은 키워드 공유글이다. 상세한 설명 대신 키워드 위주의 설명이므로 해당 키워드로 검색하면 많은 자료가 나올 것이다.
ViewModel 의 lifecycle 은 Activity 의 lifecycle 보다 더 길다. 그림에서도 볼 수 있듯이 Activity 가 단순히 파괴되는 시점이 아닌 완전히 활동을 끝낼 때, ViewModel 의 onCleared() 함수가 호출되고 데이터가 파괴되는 과정을 거친다. 그러므로 configuration change 가 발생할 때 유지해야하는 데이터는 ViewModel에 저장하는 것이 좋다. 또한 ViewModel의 생성자 매개변수로 SavedStateHandle을 정의하여 ViewModel 내부에서 직접 bundle의 데이터를 설정하거나 꺼내 사용하는 방법도 있다.
configuration change 가 일어날 때, ui state를 유지하고 싶다면 onSavedInstanceState() 를 이용해 bundle 에 state를 담고, 뷰가 재생성된 뒤 onViewStateRestored() 시점에 bundle에 담은 state를 꺼내 셋팅해주는 것이 좋다.
Manifest의 configChanges 옵션을 적용하면 Activity의 Configuration Changes를 다룰 수 있으며, 다양한 옵션들이 존재한다. configChanges 옵션 유무에 따라 호출되는 lifecycle 에 변동이 생기게 되므로 적절하게 채택하여 사용하면 좋다.
1.
Given; Manifest에 `android:configChanges` 가 없는 상태
When; Configuration Change 가 발생한 경우
Then; Activity가 재생성된다.
* lifecycle은 onStop() > onDestroy() (Activity 파괴) > onCreate() (Activity 재 생성) > ...
2.
Given; Manifest에 `android:configChanges` 이 추가된 상태
When; Configuration Change 가 발생한 경우
Then; Activity가 재생성되지 않는다.
* lifecycle이 다시 시작되지 않고, onConfigurationChanged() 만 호출.
RecycleView에서 Configuration Change 가 발생하는 경우에 Scroll Position을 유지하고 싶은 경우 position 이나 offset을 저장하는 방법이 있겠지만, 별개로 RecyclerView의 stateRestorationPolicy 옵션을 통해 설정할 수 있다.
recyclerView.adapter.stateRestorationPolicy = RecyclerView.Adapter.StateRestorationPolicy.ALLOW
위와같이 설정할 수 있으며, 기본적으로 stateRestorationPolicy은 ALLOW
가 default로 설정되어 있다.
각 옵션에 대해 설명하자면,
1. ALLOW
- 항상 어댑터의 상태를 저장한다.
2. PREVENT
- 어댑터의 상태를 저장하지 않는다.
3. PREVENT_WHEN_EMPTY
- 어댑터로부터 설정되는 리스트가 1개 이상일 때 상태를 저장한다.
또는 LayoutManager 자체를 저장할 수도 있다.
//save
val recyclerViewState = recyclerView.layoutManager.onSaveInstanceState()
//restore
recyclerView.layoutManager.onRestoreInstanceState(recyclerViewState)
해상도 별로 View의 설정 값(width, height, margin etc,..)을 다르게 적용하고 싶은 경우 dimens.xml
을 이용하면 된다.
다만 해상도 별 절대값으로 대응하고자 할 때는 간단하게 적용할 수 있는 방법이지만, 디자인측에서 상대값으로 대응하고자 하는 경우에는 Constraint Layout 을 이용하거나, 별도의 device screen에 비례하는 size를 programmatically 계산해서 적용할 수 있겠다.
아래는 일반적인 디바이스 화면 크기를 나누는 기준이다.
이를 바탕으로 layout-sw600dp 폴더를 생성하는 경우 아래와 같이 경로를 설정할 수 있는데,
res/layout/main_activity.xml # For handsets (smaller than 600dp available width)
res/layout-sw600dp/main_activity.xml # For 7” tablets (600dp wide and bigger)
여기서 sw600dp 의 "sw" 란, smallestWidth 의 줄임말로 최소 지원 디바이스 크기를 정할 때 사용되는 suffix로 사용된다. 결국 layout-sw600dp
의 의미는 "디바이스 가로 크기가 600dp를 넘기는 경우 layout-sw600dp 경로에 있는 layout resource 를 사용한다." 이다.
이런방법으로 layout 폴더 생성 시 규칙을 정하면 내가 원하는 범위에 해당하는 레이아웃이 설정된다.
이 외에도 폴더 이름을 설정할 때 사용할 수 있는 여러가지 한정자가 있으므로 참고하면 좋다.