Проблема обновления RecyclerView после фрагмента диалога - PullRequest
0 голосов
/ 02 февраля 2020

Я использую навигационную архитектуру Jetpack с navhost, navgraph и библиотекой базы данных Room SQLite. В моем приложении к каждой категории добавлены задачи. В одном из моих фрагментов под названием CategoryFragment все задачи в определенной категории c перечислены в RecyclerView, который я получаю, вызывая оператор SQL и передавая ему categoryId.

У меня также есть FAB в этом фрагменте, который при нажатии выскакивает фрагмент диалога под названием NewTaskDialogFragment. В этом диалоговом окне пользователь вводит название и описание задачи. Нажатие кнопки ОК добавит задачу в базу данных, а затем вернет backstack в go обратно в CategoryFragment. Но это не перезагружает CategoryFragment и впоследствии не выполняет вызов SQL для извлечения задач из базы данных и обновления RecyclerView. Фактически, ни один из методов жизненного цикла не вызывается на CategoryFragment.

Чтобы исправить это, я попробовал другой подход и использовал SafeArgs для передачи имени и описания задачи в CategoryFragment, но это вызывает другую проблему, при которой система снова добавляет CategoryFragment в backstack. так что мне нужно дважды нажать кнопку возврата, чтобы go вернуться к предыдущему фрагменту в backstack перед CategoryFragment. Итак, как лучше всего выполнить sh задачу вставки данных из диалогового окна в базу данных и одновременно обновить RecyclerView? Спасибо.

CategoryFragment

package com.example.pomoplay.ui.main

import android.content.Context
import android.os.Build
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.SearchView
import androidx.fragment.app.FragmentTransaction
import androidx.fragment.app.activityViewModels
import androidx.navigation.NavController
import androidx.navigation.Navigation
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.pomoplay.PomoPlayObservablesSingleton
import com.example.pomoplay.R
import com.example.pomoplay.TasksRecyclerAdapter
import kotlinx.android.synthetic.main.fragment_categories.*
import kotlinx.android.synthetic.main.fragment_category.*

class CategoryFragment : Fragment(), SearchView.OnQueryTextListener {

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

    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)
        }

        navController = Navigation.findNavController(view)

        showTasks()

    }

    private fun showTasks() {

        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())
        }
    }

    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
            }
        })
    }

    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
    }

    override fun onQueryTextChange(newText: String?): Boolean {

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

        return false
    }

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

}

NewTaskDialogFragment

class NewTaskDialogFragment : DialogFragment() {
private lateinit var taskNameEditText: EditText
private lateinit var taskDescEditText: EditText
private lateinit var navController: NavController
private val viewModel: CategoryTasksViewModel by activityViewModels()

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    super.onCreateDialog(savedInstanceState)

    navController = Navigation.findNavController(parentFragment?.view!!)

    var catList = ArrayList<String>()
    catList.add("Test Item 1")
    catList.add("Test Item 2")

    val view =
        requireActivity().layoutInflater.inflate(R.layout.fragment_new_task_dialog, null)

    taskNameEditText = view.findViewById(R.id.dialog_new_task_name) as EditText
    taskDescEditText = view.findViewById(R.id.dialog_new_task_desc) as EditText

    return activity?.let { it ->

        // Use the Builder class for convenient dialog construction

        val builder = AlertDialog.Builder(it)
        builder.setTitle("Testing")
            .setPositiveButton(
                "ok"
            ) { _, id ->

           var task = PomoTask(taskNameEditText.text.toString().trim().replace("\\s+".toRegex(), " "), taskDescEditText.text.toString().trim().replace("\\s+"," "))

                task.categoryId = viewModel.getCategoryId()

                viewModel.insertTask(task)

                navController.popBackStack()

            }
            .setNegativeButton("cancel") { _, id ->

            }
            .setView(view)


        var spinner = view.findViewById<Spinner>(R.id.dialog_new_task_spinner)

        var spinnerAdapter =
            context?.let {
                ArrayAdapter<String>(
                    it,
                    android.R.layout.simple_spinner_item,
                    catList
                )
            }


        spinnerAdapter?.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
        spinner.adapter = spinnerAdapter



        val dialog = builder.create()

        dialog.setOnShowListener { dialog ->
            (dialog as AlertDialog).getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = taskNameEditText.text.isNotBlank() && taskNameEditText.text.isNotEmpty()
        }

        taskNameEditText.addTextChangedListener(object : TextWatcher {
            override fun onTextChanged(
                s: CharSequence, start: Int, before: Int,
                count: Int
            ) {
            }

            override fun beforeTextChanged(
                s: CharSequence, start: Int, count: Int,
                after: Int
            ) {
            }

            override fun afterTextChanged(s: Editable) { // Check if edittext is empty

                dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled =
                    !(taskNameEditText.text.isBlank() || taskNameEditText.text.isEmpty())


            }

        })

        dialog

    } ?: throw IllegalStateException("Activity cannot be null")
}
}

TasksRecyclerAdapter

class TasksRecyclerAdapter(private val context: Context) : RecyclerView.Adapter<TasksRecyclerAdapter.ViewHolder>() {

private var pomoTasksList: List<PomoTask> = emptyList()
private val layoutInflater = LayoutInflater.from(context)

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    val itemView = layoutInflater.inflate(R.layout.tasks_list_item, parent, false)
    return ViewHolder(itemView)
}

fun setTasksList(tasks: List<PomoTask>) {
    pomoTasksList = tasks
    notifyDataSetChanged()
}

override fun getItemCount() = pomoTasksList.size


override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    val category = pomoTasksList[position]
    holder.textTaskTitle?.text = category?.name
    holder.textTaskDescription?.text = category?.desc

    holder.taskOptMenu.setOnClickListener {
        val popup = PopupMenu(context, holder.taskOptMenu)
        //inflating menu from xml resource
        //inflating menu from xml resource
        popup.inflate(R.menu.category_menu)
        //adding click listener
        //adding click listener
        popup.setOnMenuItemClickListener(object : MenuItem.OnMenuItemClickListener,
            PopupMenu.OnMenuItemClickListener {
            override fun onMenuItemClick(item: MenuItem): Boolean {
                return when (item.itemId) {
                    R.id.app_settings -> {
                        Toast.makeText(context, "it works from recyclerview! :)", Toast.LENGTH_SHORT).show()
                        true
                    }
                    else -> false
                }
            }
        })

        popup.show()
    }
}

class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    val textTaskTitle = itemView.findViewById<TextView?>(R.id.tasks_list_item_title)
    val textTaskDescription = itemView.findViewById<TextView?>(R.id.tasks_list_item_description)
    val taskOptMenu: ImageView = itemView.findViewById(R.id.tasks_list_optmenu)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...