SavedStateHandle 返回空值

SavedStateHandle returning null values

我有一个 ActionBar 菜单图标可以打开 CategoryFragment。此片段接受从另一个片段传递的 category 对象 SafeArgs 参数。在 CategoryFragment 中,我将 category 的名称和 ID 作为 SavedStateHandle 值存储到片段的共享 ViewModel 中。我已对其进行设置,以便该片段在需要时使用存储的 SavedStateHandle 值作为类别名称和 ID。例如,CategoryFragment 第一次使用从发送片段传递的类别对象,但随后创建 CategoryFrgament 将使用 SavedStateHandle 值。

问题是,如果在第一次打开 CategoriesFragment 之后,然后通过按 phone 的物理后退按钮或从 phone 终止应用程序退出应用程序导航栏中最近的按钮,现在通过按 ActionBar 菜单图标直接打开 CategoryFragment 显示空白屏幕。这是因为从 SavedStateHandle 返回的值为空。我该如何解决这个问题?

类别片段

class CategoryFragment : Fragment(), SearchView.OnQueryTextListener {

    lateinit var navController: NavController
    private var adapter: TasksRecyclerAdapter? = null
    private val viewModel: CategoryTasksViewModel by activityViewModels()
    private var fromCategoriesFragment: Boolean = false

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_category, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        navController = Navigation.findNavController(view)

        observerSetup()
        recyclerSetup()

        var searchView = category_tasks_searchview
        searchView.setOnQueryTextListener(this)

        fab_new_task.setOnClickListener {
            navController.navigate(R.id.action_categoryFragment_to_newTaskDialogFragment)
        }

        showTasks()
    }

private fun showTasks() {

        if(fromCategoriesFragment){

            PomoPlayObservablesSingleton.fromCategoriesFragment.onNext(false)

            if (!arguments?.isEmpty!!) {

                var args = CategoryFragmentArgs.fromBundle(arguments!!)
                category_title.text = args.category?.name

                var category = args.category
                viewModel.setPomoCategoryName(category.name)
                viewModel.setCategoryId(category.id)
                viewModel.searchTasksByCategoryId(category.id)

            }

        }
        else{
            category_title.text = viewModel.getPomoCategoryName()
            viewModel.searchTasksByCategoryId(viewModel.getCategoryId())

            Log.i("CategoryFrag-CatName", viewModel.getPomoCategoryName().toString())
            Log.i("CategoryFrag-CatId", viewModel.getCategoryId().toString())
        }
    }

    private fun observerSetup() {

        viewModel.getSearchTasksByCategoryIdResults().observe(this,androidx.lifecycle.Observer { tasks ->

            if(tasks.isNotEmpty()){

                adapter?.setTasksList(tasks.sortedBy { task -> task.name?.toLowerCase() })
                task_not_found_bubble.visibility = View.GONE
                task_not_found_text.visibility = View.GONE
            }
            else{
                task_not_found_bubble.visibility = View.VISIBLE
                task_not_found_text.visibility = View.VISIBLE
            }
        })

        PomoPlayObservablesSingleton.fromCategoriesFragment.subscribe {value -> fromCategoriesFragment = value}

    }

    private fun recyclerSetup() {
        adapter = context?.let { TasksRecyclerAdapter(it) }
        tasks_list?.layoutManager = LinearLayoutManager(context)
        tasks_list?.adapter = adapter
    }

    override fun onQueryTextSubmit(query: String?): Boolean {

        Log.i("Lifecycle-CatFragment", "onQueryTextSubmit() called")

        var q = query?.toLowerCase()?.trim()?.replace("\s+".toRegex(), " ")
        setLastSearchQuery(q.toString())

        viewModel.searchTasksByName(viewModel.getLastSearchQuery().toString())

        return false
    }

    private fun setLastSearchQuery(lastSearchQuery: String) {
        viewModel.setLastSearchQuery(lastSearchQuery)
    }
}

CategoryTasksViewModel

class CategoryTasksViewModel(application: Application, state: SavedStateHandle) : AndroidViewModel(application) {

    private val repository: PomoPlayRepository = PomoPlayRepository(application)
    private val allCategories: LiveData<List<Category>>?
    private val allPomoTasks: LiveData<List<PomoTask>>?
    private val searchCategoriesByNameResults: MutableLiveData<List<Category>>
    private val searchCategoryByIdResults: MutableLiveData<Category>
    private val searchTasksByIdResults: MutableLiveData<PomoTask>
    private val searchTasksByNameResults: MutableLiveData<List<PomoTask>>
    private val searchTasksByCategoryIdResults: MutableLiveData<List<PomoTask>>

    private val savedStateHandle = state

    companion object{

        private const val LAST_SEARCH_QUERY = "lastSearchQuery"

    }

    init {
        allCategories = repository.allCategories
        allPomoTasks = repository.allPomoTasks
        searchTasksByIdResults = repository.searchTasksByIdResults
        searchTasksByNameResults = repository.searchTasksByNameResults
        searchTasksByCategoryIdResults = repository.searchTasksByCategoryIdResults
        searchCategoryByIdResults = repository.searchCategoriesByIdResults
        searchCategoriesByNameResults = repository.searchCategoriesByNameResults
    }

    fun setLastSearchQuery(lastSearchName: String){
        savedStateHandle.set(LAST_SEARCH_QUERY, lastSearchName)
    }

    fun getLastSearchQuery(): String?{
        return savedStateHandle.get<String>(LAST_SEARCH_QUERY)
    }

    fun setPomoCategoryName(name: String?){
        savedStateHandle.set("categoryName", name)
    }

    fun getPomoCategoryName(): String?{
        return savedStateHandle.get<String>("categoryName")
    }

    fun setCategoryId(id: Int){
        savedStateHandle.set("categoryId", id)
    }

    fun getCategoryId(): Int?{
        return savedStateHandle.get<Int>("categoryId")
    }

    fun insertTask(pomoTask: PomoTask?) {
        repository.insertTask(pomoTask)
    }

    fun deleteTask(pomoTask: PomoTask) {
        repository.deleteTask(pomoTask)
    }

    fun updateTask(pomoTask: PomoTask) {
        repository.updateTask(pomoTask)
    }


    fun searchTasksByName(name: String) {
        repository.searchTasksByName(name)
    }


    fun searchTasksById(pomoTaskId: Int){
        repository.searchTasksById(pomoTaskId)
    }

    fun searchTasksByCategoryId(categoryId: Int?){
        repository.searchTasksByCategoryId(categoryId)
    }

    fun getAllPomoTasks() : LiveData<List<PomoTask>>? {
        return allPomoTasks
    }

    fun getSearchTasksbyNameResults() : MutableLiveData<List<PomoTask>> {
        return searchTasksByNameResults
    }

    fun getSearchTasksByIdResults() : MutableLiveData<PomoTask> {
        return searchTasksByIdResults
    }

    fun getSearchTasksByCategoryIdResults() : MutableLiveData<List<PomoTask>> {
        return searchTasksByCategoryIdResults
    }

}

SavedStateHandle 的设计目的不是您希望它做的:它 ...

... 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.

被系统杀死,如果用户故意关闭应用程序甚至破坏(“永久导航”)作为其范围的Fragment/Activity则不会。请参阅 Saving UI State - User-initiated UI state dismissal:

上的文档

The user's assumption in these complete dismissal cases is that they have permanently navigated away from the activity, and if they re-open the activity they expect the activity to start from a clean state. The underlying system behavior for these dismissal scenarios matches the user expectation - the activity instance will get destroyed and removed from memory, along with any state stored in it and any saved instance state record associated with the activity.

也许可以将您希望在场景中幸存下来的信息保存在 SharedPreferences