Skip to content

Commit b21f341

Browse files
ADFA-3418: Release editors when the editor activity is recreated
A recreate (dark mode, locale) destroys EditorHandlerActivity without closing its editors, so each editor's EditorEventDispatcher job kept the IDEEditor and the destroyed activity on a coroutine worker (425 KB in a LeakCanary dump), alongside the EventBus and breakpoint-listener paths fixed earlier. preDestroy now calls CodeEditorView.release() on a non-finishing destroy. release() is close() without notifyClose() - a DocumentCloseEvent could reach the language server after the new activity reopens the file - and without shutting readWriteContext, which an in-flight save may still be writing through.
1 parent bbb2b4c commit b21f341

2 files changed

Lines changed: 24 additions & 6 deletions

File tree

‎app/src/main/java/com/itsaky/androidide/activities/editor/EditorHandlerActivity.kt‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import androidx.collection.MutableIntObjectMap
3737
import androidx.core.content.IntentCompat
3838
import androidx.core.content.res.ResourcesCompat
3939
import androidx.core.view.GravityCompat
40+
import androidx.core.view.children
4041
import androidx.core.view.doOnNextLayout
4142
import androidx.fragment.app.Fragment
4243
import androidx.fragment.app.FragmentManager
@@ -264,6 +265,17 @@ open class EditorHandlerActivity :
264265
override fun provideEditorAt(index: Int): CodeEditorView? = getEditorAtIndex(index)
265266

266267
override fun preDestroy() {
268+
// A recreate (dark mode, locale) destroys this instance without closing its editors, and their
269+
// dispatcher job, EventBus registration and breakpoint listener kept it alive. Finishing closes
270+
// them through doCloseAll() instead.
271+
if (!isDestroying) {
272+
_binding
273+
?.content
274+
?.editorContainer
275+
?.children
276+
?.filterIsInstance<CodeEditorView>()
277+
?.forEach { it.release() }
278+
}
267279
super.preDestroy()
268280
// TSLanguageRegistry.instance is a process-wide singleton whose own KDoc says destroy() "must
269281
// be called only when the application is exiting" -- guarded on didCompleteLiveOnCreate (same

‎app/src/main/java/com/itsaky/androidide/ui/CodeEditorView.kt‎

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -818,14 +818,20 @@ class CodeEditorView(
818818
}
819819

820820
override fun close() {
821+
_binding?.editor?.notifyClose()
822+
release()
823+
readWriteContext.use { }
824+
}
825+
826+
/**
827+
* Drops what ties this editor to the activity, for a recreate that reopens the same file in a new
828+
* editor. Unlike [close] it neither tells the language server the file closed (that event can land
829+
* after the reopen) nor shuts [readWriteContext], since a save may still be writing through it.
830+
*/
831+
fun release() {
821832
codeEditorScope.cancelIfActive("Cancellation was requested")
822833
debugClient.breakpoints.removeListener(this)
823-
_binding?.editor?.apply {
824-
notifyClose()
825-
release()
826-
}
827-
828-
readWriteContext.use { }
834+
_binding?.editor?.release()
829835
}
830836

831837
private fun changeFontSizeBy(delta: Float) {

0 commit comments

Comments
 (0)