Skip to content

Conversation

@ShaanNarendran
Copy link
Contributor

@ShaanNarendran ShaanNarendran commented Jan 17, 2026

Purpose / Description

This bug happens when you tap add too many times in a small window, it ends up crashing ankidroid

Fixes

Approach

Tried different approaches like using a boolean variable and mutex before realising that the issue was with the lifecycle in savenote()

How Has This Been Tested?

I used an auto clicker to simulate a lot of clicks a second (1 ms interval) and the app would just crash immediately, after applying the change however it just takes the first click and performs the add

Checklist

Please, go through these checks before submitting the PR.

  • You have a descriptive commit message with a short title (first line, max 50 chars).
  • You have commented your code, particularly in hard-to-understand areas
  • You have performed a self-review of your own code
  • UI changes: include screenshots of all affected screens (in particular showing any new or changed strings)
  • UI Changes: You have tested your change using the Google Accessibility Scanner

Copy link
Member

@david-allison david-allison left a comment

Choose a reason for hiding this comment

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

This one nerd-sniped me, I tried something like this a couple of years ago, but wasn't happy with it.

Here's a thought I had now. Untested, but I feel it implements your logic nicely

Subject: [PATCH] A
---
Index: AnkiDroid/src/main/java/com/ichi2/anki/NoteEditorFragment.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/NoteEditorFragment.kt b/AnkiDroid/src/main/java/com/ichi2/anki/NoteEditorFragment.kt
--- a/AnkiDroid/src/main/java/com/ichi2/anki/NoteEditorFragment.kt	(revision fa83782d721bf044805f1c9f2297a28cde3a7757)
+++ b/AnkiDroid/src/main/java/com/ichi2/anki/NoteEditorFragment.kt	(date 1768737838195)
@@ -153,6 +153,7 @@
 import com.ichi2.anki.snackbar.SnackbarBuilder
 import com.ichi2.anki.snackbar.showSnackbar
 import com.ichi2.anki.ui.setupNoteTypeSpinner
+import com.ichi2.anki.utils.RunOnlyOnce
 import com.ichi2.anki.utils.ext.sharedPrefs
 import com.ichi2.anki.utils.ext.showDialogFragment
 import com.ichi2.anki.utils.ext.window
@@ -224,7 +225,7 @@
     private var changed = false
     private var isTagsEdited = false
     private var isFieldEdited = false
-
+    private var addNoteJob = RunOnlyOnce(scope = lifecycleScope)
     private var multimediaActionJob: Job? = null
 
     private val getColUnsafe: Collection
@@ -1338,7 +1339,7 @@
 
             reloadRequired = true
 
-            lifecycleScope.launch {
+            addNoteJob.launch {
                 val noteFieldsCheck = checkNoteFieldsResponse(editorNote!!)
                 if (noteFieldsCheck is NoteFieldsCheckResult.Failure) {
                     addNoteErrorMessage = noteFieldsCheck.localizedMessage ?: getString(R.string.something_wrong)
Index: AnkiDroid/src/main/java/com/ichi2/anki/utils/OnlyOnce.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/utils/OnlyOnce.kt b/AnkiDroid/src/main/java/com/ichi2/anki/utils/OnlyOnce.kt
--- a/AnkiDroid/src/main/java/com/ichi2/anki/utils/OnlyOnce.kt	(revision fa83782d721bf044805f1c9f2297a28cde3a7757)
+++ b/AnkiDroid/src/main/java/com/ichi2/anki/utils/OnlyOnce.kt	(date 1768737821418)
@@ -16,7 +16,9 @@
 
 package com.ichi2.anki.utils
 
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
 import timber.log.Timber
 
 /**
@@ -51,3 +53,15 @@
         }
     }
 }
+
+class RunOnlyOnce(private val scope: CoroutineScope) {
+    private var job: Job? = null
+
+    fun launch(block: suspend CoroutineScope.() -> Unit) {
+        if (job?.isActive == true) {
+            Timber.d("skipped multiple executions of job")
+            return
+        }
+        job = scope.launch(block = block)
+    }
+}
\ No newline at end of file

@david-allison david-allison added Needs Second Approval Has one approval, one more approval to merge and removed Needs Review labels Jan 18, 2026
@ShaanNarendran

This comment was marked as outdated.

Copy link
Member

@david-allison david-allison left a comment

Choose a reason for hiding this comment

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

LGTM, assuming it's tested

Optional:

  • add Fixes 17375 to the commit message description (without the #) to help anyone looking through the history
  • Add a co-author: Co-authored-by: David Allison <62114487+david-allison@users.noreply.github.com> via a trailer at the end of the commit description if you feel a contribution was meaningful enough to warrant a pip on their GitHub heatmap for the change

… editor

Fixes 17375

Co-authored-by: David Allison <62114487+david-allison@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Needs Second Approval Has one approval, one more approval to merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NoteEditor: Crashes when tapping 'add' too much: BackendDbFileTooOldException: called Result::unwrap() on an Err value: PoisonError { .. }

2 participants