onSaveInstanceState → SavedStateHandle

3 阅读1分钟

onSaveInstanceState → SavedStateHandle

老写法(Java)

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putString("query", currentQuery);
    outState.putInt("page", currentPage);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState != null) {
        currentQuery = savedInstanceState.getString("query");
        currentPage = savedInstanceState.getInt("page");
    }
}

问题在哪里

Activity 和 Fragment 要各自写保存/恢复逻辑。判断 savedInstanceState != null 然后是各种 get 方法的样板代码。如果用了 ViewModel,数据虽然在内存里不丢,但进程被杀死后还是没了。

新写法(ViewModel + SavedStateHandle)

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

    // 写法 1:直接读/写
    var query: String
        get() = savedStateHandle.get<String>("query") ?: ""
        set(value) = savedStateHandle.set("query", value)

    // 写法 2:用 StateFlow
    private val _page = savedStateHandle.getStateFlow("page", 1)
    val page: StateFlow<Int> = _page

    fun nextPage() {
        savedStateHandle.set("page", page.value + 1)
    }
}

// Activity 里不再需要 onSaveInstanceState 和手动恢复
class SearchActivity : AppCompatActivity() {
    private val viewModel: SearchViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ViewModel 里的数据通过 SavedStateHandle 自动恢复
    }
}

一句话注意

SavedStateHandle 在进程被杀死后也能恢复数据——数据会被序列化保存到 onSaveInstanceState 的 Bundle 里,进程重建后自动恢复。但能保存的数据类型有限制:基本类型、String、Parcelable、Serializable 等。大对象或复杂引用不能用这个存。

ViewModel + SavedStateHandle 结合后,Activity/Fragment 的 onSaveInstanceState 基本可以从代码里删了——UI 相关的临时状态都交给 ViewModel 管理。


Java Android 老项目迁移系列,持续更新中。