Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 8 additions & 12 deletions AnkiDroid/src/main/java/com/ichi2/anki/dialogs/FlagRenameDialog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.ichi2.anki.Flag
import com.ichi2.anki.R
import com.ichi2.anki.databinding.RenameFlagLayoutBinding
import com.ichi2.utils.customView
import com.ichi2.utils.title
import kotlinx.coroutines.launch
Expand All @@ -37,20 +37,16 @@ import timber.log.Timber
* A DialogFragment for renaming flags through a RecyclerView.
*/
class FlagRenameDialog : DialogFragment() {
private lateinit var recyclerView: RecyclerView
private lateinit var flagAdapter: FlagAdapter

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialogView = requireActivity().layoutInflater.inflate(R.layout.rename_flag_layout, null)
val binding = RenameFlagLayoutBinding.inflate(requireActivity().layoutInflater)
val builder =
AlertDialog.Builder(requireContext()).apply {
customView(view = dialogView, 4, 4, 4, 4)
customView(view = binding.root, 4, 4, 4, 4)
title(R.string.rename_flag)
}
val dialog = builder.create()

recyclerView = dialogView.findViewById(R.id.recyclerview_flags)
setupRecyclerView()
setupRecyclerView(binding)
return dialog
}

Expand All @@ -67,13 +63,13 @@ class FlagRenameDialog : DialogFragment() {
)
}

private fun setupRecyclerView() =
private fun setupRecyclerView(binding: RenameFlagLayoutBinding) =
requireActivity().lifecycleScope.launch {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @david-allison, I found a lifecycle scope mismatch here. This function is launched on Activity scope, but update a DialogFragment view after suspension. If the dialog is dismissed before createFlagList() resumes, you risk touching a dead view, potentially crashing after dismiss.

Instead, let's tie the job to the dialog's view lifecycle:

lifecycleScope.launch {
    val items = withContext(Dispatchers.IO) { createFlagList() }
    val adapter = FlagAdapter(lifecycleScope = lifecycleScope)
    binding.recyclerViewFlags.layoutManager = LinearLayoutManager(requireContext())
    binding.recyclerViewFlags.adapter = adapter
    adapter.submitList(items)
}

val flagItems = createFlagList()
flagAdapter = FlagAdapter(lifecycleScope = lifecycleScope)
recyclerView.adapter = flagAdapter
val flagAdapter = FlagAdapter(lifecycleScope = lifecycleScope)
binding.recyclerViewFlags.adapter = flagAdapter
flagAdapter.submitList(flagItems)
recyclerView.layoutManager = LinearLayoutManager(requireContext())
binding.recyclerViewFlags.layoutManager = LinearLayoutManager(requireContext())
}

private suspend fun createFlagList(): List<FlagItem> {
Expand Down
2 changes: 1 addition & 1 deletion AnkiDroid/src/main/res/layout/rename_flag_layout.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
android:layout_height="match_parent">

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview_flags"
android:id="@+id/recycler_view_flags"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

Expand Down