프래그먼트로 상태 저장

다양한 Android 시스템 작업은 프래그먼트 상태에 영향을 미칠 수 있습니다. Android 프레임워크에서는 사용자 상태가 저장되도록 프래그먼트와 백 스택을 자동으로 저장하고 복원합니다. 따라서 프래그먼트의 모든 데이터도 저장되고 복원되도록 해야 합니다.

다음 표는 프래그먼트가 상태를 잃게 만드는 작업과 함께 다양한 유형의 상태가 이러한 변경에도 지속되는지를 간략하게 설명합니다. 표에서 언급된 상태 유형은 다음과 같습니다.

  • 변수: 프래그먼트의 로컬 변수
  • 뷰 상태: 프래그먼트의 뷰 하나 이상에서 소유한 모든 데이터
  • SavedState: onSaveInstanceState()에 저장되어야 하는 이 프래그먼트 인스턴스에 고유한 데이터
  • NonConfig: 서버 또는 로컬 저장소와 같은 외부 소스에서 가져온 데이터 또는 커밋된 후 서버에 전송되는 사용자 생성 데이터

변수는 종종 SavedState와 동일하게 간주되지만 다음 표에서는 두 가지를 구별하여 다양한 작업이 각각에 미치는 영향을 보여 줍니다.

작업 변수 뷰 상태 SavedState NonConfig
백 스택에 추가됨 x
구성 변경 x
프로세스 중단/재생성 x ✓*
백 스택에 추가되지 않고 삭제됨 x x x x
호스팅 완료됨 x x x x

* NonConfig 상태는 ViewModel의 저장된 상태 모듈을 사용하여 프로세스 종료 시에도 유지될 수 있습니다.

표 1: 프래그먼트를 파괴하는 다양한 작업과 이러한 작업이 여러 상태 유형에 미치는 영향

구체적인 예를 살펴보겠습니다. 임의의 문자열을 생성하여 TextView에 표시하고 친구에게 전송하기 전에 문자열을 수정하는 옵션을 제공하는 화면을 생각해 보세요.

다양한 상태 유형을 보여 주는 임의의 텍스트 생성기 앱
그림 1. 다양한 상태 유형을 보여 주는 임의의 텍스트 생성기 앱

이 예에서는 사용자가 수정 버튼을 누르면 앱에서 사용자가 메시지를 수정할 수 있는 EditText 뷰를 표시한다고 가정합니다. 사용자가 취소를 클릭하면 EditText 뷰가 지워지고 공개 상태가 View.GONE으로 설정되어야 합니다. 이러한 화면이 원활하게 작동하려면 다음과 같은 4가지 데이터 관리가 필요합니다.

데이터 유형 상태 유형 설명
seed Long NonConfig 새로운 좋은 동작을 무작위로 생성하는 데 사용되는 시드입니다. ViewModel이 만들어지면 생성됩니다.
randomGoodDeed String SavedState + 변수 프래그먼트가 맨 처음 만들어질 때 생성됩니다. randomGoodDeed는 프로세스 종료 및 재생성 후에도 사용자가 동일한 임의의 좋은 동작을 볼 수 있도록 저장됩니다.
isEditing Boolean SavedState + 변수 불리언 플래그는 사용자가 수정을 시작하면 true로 설정됩니다. isEditing은 프래그먼트가 다시 만들어질 때 화면의 수정 부분이 계속 표시되도록 저장됩니다.
수정된 텍스트 Editable 뷰 상태(EditText 소유) EditText 뷰에서 수정된 텍스트입니다. EditText 뷰는 사용자의 진행 중인 변경사항이 손실되지 않도록 이 텍스트를 저장합니다.

표 2: 무작위 텍스트 생성기 앱에서 관리해야 하는 상태입니다.

다음 섹션에서는 파괴적인 작업을 통해 데이터 상태를 올바르게 관리하는 방법을 설명합니다.

뷰 상태

뷰는 자체 상태를 관리합니다. 예를 들어 뷰에서 사용자 입력을 수락하면 이 입력을 저장하고 복원하여 구성 변경을 처리하는 것은 뷰가 책임집니다. Android 프레임워크에서 제공하는 모든 뷰에는 자체 onSaveInstanceState()onRestoreInstanceState()의 구현이 있으므로 프래그먼트 내에서 뷰 상태를 관리하지 않아도 됩니다.

예를 들어 이전 시나리오에서는 수정된 문자열이 EditText에 보관됩니다. EditText는 표시하는 텍스트의 값뿐 아니라 선택된 텍스트의 시작 및 끝과 같은 기타 세부정보를 알고 있습니다.

뷰 상태를 유지하려면 뷰에 ID가 필요합니다. 이 ID는 프래그먼트와 프래그먼트의 뷰 계층 구조 내에서 고유해야 합니다. ID가 없는 뷰는 상태를 유지할 수 없습니다.

<EditText
    android:id="@+id/good_deed_edit_text"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

표 1에서 언급했듯이 뷰는 프래그먼트를 삭제하거나 호스트를 제거하지 않는 모든 작업을 통해 ViewState를 저장하고 복원합니다.

SavedState

프래그먼트는 프래그먼트의 작동 방식에 필수적인 소량의 동적 상태를 관리합니다. Fragment.onSaveInstanceState(Bundle)를 사용하여 쉽게 직렬화된 데이터를 유지할 수 있습니다. Activity.onSaveInstanceState(Bundle)와 마찬가지로 번들에 배치하는 데이터는 구성 변경과 프로세스 종료 및 재생성을 통해 유지되고 프래그먼트의 onCreate(Bundle), onCreateView(LayoutInflater, ViewGroup, Bundle), onViewCreated(View, Bundle) 메서드에서 사용할 수 있습니다.

이전 예를 계속 진행하면 randomGoodDeed는 사용자에게 표시되는 동작이고 isEditing은 프래그먼트가 EditText를 표시하는지 숨기는지 판단하는 플래그입니다. 이 저장된 상태는 다음 예와 같이 onSaveInstanceState(Bundle)를 사용하여 유지해야 합니다.

Kotlin

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    outState.putBoolean(IS_EDITING_KEY, isEditing)
    outState.putString(RANDOM_GOOD_DEED_KEY, randomGoodDeed)
}

Java

@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putBoolean(IS_EDITING_KEY, isEditing);
    outState.putString(RANDOM_GOOD_DEED_KEY, randomGoodDeed);
}

onCreate(Bundle)에서 상태를 복원하려면 번들에서 저장된 값을 검색합니다.

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    isEditing = savedInstanceState?.getBoolean(IS_EDITING_KEY, false)
    randomGoodDeed = savedInstanceState?.getString(RANDOM_GOOD_DEED_KEY)
            ?: viewModel.generateRandomGoodDeed()
}

Java

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState != null) {
        isEditing = savedInstanceState.getBoolean(IS_EDITING_KEY, false);
        randomGoodDeed = savedInstanceState.getString(RANDOM_GOOD_DEED_KEY);
    } else {
        randomGoodDeed = viewModel.generateRandomGoodDeed();
    }
}

표 1에서 언급했듯이 변수는 프래그먼트가 백 스택에 배치되면 유지됩니다. 변수를 저장된 상태로 취급하면 파괴적인 작업이 수행되어도 유지됩니다.

NonConfig

NonConfig 데이터는 프래그먼트 외부(예: ViewModel)에 배치해야 합니다. 위의 예에서 seed(NonConfig 상태)는 ViewModel에서 생성됩니다. 상태를 유지하는 로직은 ViewModel에서 소유합니다.

Kotlin

public class RandomGoodDeedViewModel : ViewModel() {
    private val seed = ... // Generate the seed

    private fun generateRandomGoodDeed(): String {
        val goodDeed = ... // Generate a random good deed using the seed
        return goodDeed
    }
}

Java

public class RandomGoodDeedViewModel extends ViewModel {
    private Long seed = ... // Generate the seed

    private String generateRandomGoodDeed() {
        String goodDeed = ... // Generate a random good deed using the seed
        return goodDeed;
    }
}

ViewModel 클래스는 기본적으로 화면 회전과 같은 구성 변경에도 데이터를 유지할 수 있으며 프래그먼트가 백 스택에 배치되면 메모리에 유지됩니다. 프로세스 종료 및 재생성 후 ViewModel이 다시 생성되고 새 seed가 생성됩니다. SavedState 모듈을 ViewModel에 추가하면 ViewModel이 프로세스 종료 및 재생성을 통해 간단한 상태를 유지할 수 있습니다.

추가 리소스

프래그먼트 상태 관리에 관한 자세한 내용은 다음 추가 리소스를 참고하세요.

Codelab

가이드