Android Dev/NowInAndroid / / 2022. 10. 25. 14:00

SavedStateHandle 사용

먼저, SavedStateHandle.kt 의 첫부분의 설명은 아래와 같다.

 

https://developer.android.com/reference/kotlin/androidx/lifecycle/SavedStateHandle

A handle to saved state passed down to androidx.lifecycle.ViewModel. You should use SavedStateViewModelFactory if you want to receive this object in ViewModel's constructor.
This is a key-value map that will let you write and retrieve objects to and from the saved state. These values will persist after the process is killed by the system and remain available via the same object.
You can read a value from it via get or observe it via androidx.lifecycle.LiveData returned by getLiveData.
You can write a value to it via set or setting a value to androidx.lifecycle.MutableLiveData returned by getLiveData.

 

1. 저장된 state를 ViewModel에 전달하는 Handle이다.

2. ViewModel's constructor안에 있는 this object를 얻으려면 SavedStateViewModelFactory 를 사용하여야한다.

3. 쓰고 불러들이는 object는 key-value이다.

4. 프로세스가 system에 의해 죽게 되더라도, values는 유지된다.

5. getLiveData에 의해 LiveData를 via하여 value를 observe or get하여 read할 수 있다.

6. 5와 마찬가지 방법으로 set or setting a value할 수 있다.

 

 

 

https://developer.android.com/topic/libraries/architecture/viewmodel-savedstate?hl=ko 

사용법 요약 : 

1.  Fragment 1.2.0 또는 전이 종속 항목인 Activity 1.1.0부터는 SavedStateHandle ViewModel의 생성자 인수로 사용할 수 있습니다.

class SavedStateViewModel(private val state: SavedStateHandle) : ViewModel() { ... }
class MainFragment : Fragment() {
    val vm: SavedStateViewModel by viewModels()

    ...
}

SavedStateHandle을 사용한 작업

SavedStateHandle 클래스는 set() 메서드와 get() 메서드를 통해 저장된 상태에 데이터를 작성하고 저장된 상태에서 데이터를 검색할 수 있게 하는 키-값 맵입니다.

SavedStateHandle을 사용하면 쿼리 값이 프로세스 중단 전반에 유지되어 활동이나 프래그먼트에서 값을 수동으로 저장 및 복원하고 ViewModel에 다시 전달하지 않고도 재생성 전과 후에 동일한 필터링된 데이터 세트가 사용자에게 표시됩니다.

 

SavedStateHandle에는 키-값 맵과 상호작용할 때 예상되는 다른 메서드도 있습니다.

또한 관측 가능한 데이터 홀더를 사용하여 SavedStateHandle에서 값을 가져올 수 있습니다. 지원되는 유형 목록은 다음과 같습니다.

 

위 설명 페이지에서, StateFlow를 사용한 방법만 눈여겨 보자. lifecycle-viewmodel-compose 아티팩트는 saveable라는 키워드를 API로 사용할 수 있다. 

 

설명 : 이 API는 SavedStateHandle과 Compose의 Saver 사이의 상호 운용성을 허용하므로 맞춤 Saver rememberSaveable을 통해 저장할 수 있는 모든 State SavedStateHandle을 사용하여 저장할 수 있습니다.

 

class SavedStateViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {

    val filteredData: List<String> by savedStateHandle.saveable {
        mutableStateOf>(emptyList())
    }

    fun setQuery(query: String) {
        withMutableSnapshot {
            filteredData = query
        }
    }
}

SavedStateHandle 내에 보관된 데이터는 활동 또는 프래그먼트의 나머지 savedInstanceState와 함께 Bundle로 저장되고 복원됩니다.

 

 

비 parcelable 클래스 저장 부분

클래스가 Parcelable 또는 Serializable을 구현하지 않으며 인터페이스 중 하나를 구현하기 위해 수정할 수 없는 경우 이 클래스의 인스턴스를 SavedStateHandle에 직접 저장할 수 없습니다.

Lifecycle 2.3.0-alpha03부터 SavedStateHandle은 setSavedStateProvider() 메서드를 사용해 객체를 Bundle로 저장하는 자체 로직을 제공하여 모든 객체를 저장할 수 있습니다. SavedStateRegistry.SavedStateProvider는 저장할 상태가 포함된 Bundle을 반환하는 단일 saveState() 메서드를 정의하는 인터페이스입니다. SavedStateHandle은 상태를 저장할 준비가 되면 saveState()를 호출하여 SavedStateProvider에서 Bundle을 검색하고 연결된 키용으로 Bundle을 저장합니다.

ACTION_IMAGE_CAPTURE 인텐트를 통해 카메라 앱에서 이미지를 요청하고 카메라가 이미지를 저장해야 하는 임시 파일에 전달하는 앱의 예를 생각해 보세요. TempFileViewModel은 임시 파일을 만드는 로직을 캡슐화합니다.

private fun File.saveTempFile() = bundleOf("path", absolutePath)

private fun Bundle.restoreTempFile() = if (containsKey("path")) {
    File(getString("path"))
} else {
    null
}

class TempFileViewModel(savedStateHandle: SavedStateHandle) : ViewModel() {
    private var tempFile: File? = null
    init {
        val tempFileBundle = savedStateHandle.get<Bundle>("temp_file")
        if (tempFileBundle != null) {
            tempFile = tempFileBundle.restoreTempFile()
        }
        savedStateHandle.setSavedStateProvider("temp_file") { // saveState()
            if (tempFile != null) {
                tempFile.saveTempFile()
            } else {
                Bundle()
            }
        }
    }

    fun createOrGetTempFile(): File {
      return tempFile ?: File.createTempFile("temp", null).also {
          tempFile = it
      }
    }
}

 

NowInAndroid에서의 SavedStateHandle사용례

 

1. 아래와 같이 saveable을 통해 state를 vm에 저장하고,

//ForYouViewmodel
/**
 * The in-progress set of topics to be selected, persisted through process death with a
 * [SavedStateHandle].
 */
private var inProgressTopicSelection: Set<String> by savedStateHandle.saveable {
    mutableStateOf<Set<String>>(emptySet())
}

/**
 * The in-progress set of authors to be selected, persisted through process death with a
 * [SavedStateHandle].
 */
private var inProgressAuthorSelection by savedStateHandle.saveable {
    mutableStateOf<Set<String>>(emptySet())
}

2. viewModelScope launch에서 이를 restore한다.

fun saveFollowedInterests() {
    // Don't attempt to save anything if nothing is selected
    if (inProgressTopicSelection.isEmpty() && inProgressAuthorSelection.isEmpty()) 
    {
        return
    }

    viewModelScope.launch {
        userDataRepository.setFollowedTopicIds(inProgressTopicSelection)
        userDataRepository.setFollowedAuthorIds(inProgressAuthorSelection)
        // Clear out the old selection, in case we return to onboarding
        withMutableSnapshot {
            inProgressTopicSelection = emptySet()
            inProgressAuthorSelection = emptySet()
        }
    }
}

 

 

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유