I have an ActionBar
menu icon that opens a CategoryFragment
. This fragment takes in a category
object SafeArgs
argument passed from another fragment. In the CategoryFragment
, I store the category
's name and id into the fragment's shared ViewModel
as SavedStateHandle
values. I've setup it up so that the fragment uses the stored SavedStateHandle
values for the category name and id when it needs to. For example, for the first time, the CategoryFragment
uses the category object passed from the sending fragment, but subsequent creation of the CategoryFrgament
will use the SavedStateHandle
values.
The problem is, if after first opening CategoriesFragment
and then exiting the app by either pressing the phone's physical back button or terminating the app from the phone's recent's button in the navbar, now opening the CategoryFragment
directly by pressing the ActionBar menu icon displays a blank screen. This is because the values returned from SavedStateHandle
are null. How can I fix this?
Category Fragment
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
}
}