fix: bind templates to MainActivity's lifecycle to prevent memory leaks

This commit is contained in:
Akash Yadav
2023-05-27 18:37:42 +05:30
parent a85acbf2d0
commit 9b547f8255
7 changed files with 66 additions and 22 deletions
+1 -1
View File
@@ -131,4 +131,4 @@
<module name="AndroidIDE.treesitter.test" target="1.7" />
</bytecodeTargetLevel>
</component>
</project>
</project>
@@ -42,6 +42,7 @@ import com.itsaky.androidide.preferences.internal.confirmProjectOpen
import com.itsaky.androidide.preferences.internal.lastOpenedProject
import com.itsaky.androidide.projects.ProjectManager.projectPath
import com.itsaky.androidide.resources.R.string
import com.itsaky.androidide.templates.ITemplateProvider
import com.itsaky.androidide.utils.DialogUtils
import com.itsaky.androidide.utils.Environment
import com.itsaky.androidide.utils.flashError
@@ -114,6 +115,18 @@ class MainActivity : IDEActivity() {
this, /* onBackPressedCallback = */ onBackPressedCallback)
}
override fun onStart() {
super.onStart()
ITemplateProvider.getInstance(reload = true)
}
override fun onStop() {
super.onStop()
if (ITemplateProvider.isLoaded()) {
ITemplateProvider.getInstance().clear()
}
}
private fun onScreenChanged(screen: Int?) {
val previous = viewModel.previousScreen
if (previous != -1) {
@@ -48,6 +48,12 @@ interface ITemplateProvider {
.findFirstOrThrow()
.also { provider = it }
}
/**
* @return Whether the [ITemplateProvider] has been loaded or not.
*/
@JvmStatic
fun isLoaded() = provider != null
}
/**
@@ -63,7 +69,7 @@ interface ITemplateProvider {
* @param templateId The ID for the template.
* @return The [Template] with the given [templateId] if any, or `null`.
*/
fun getTemplate(templateId: String) : Template<*>?
fun getTemplate(templateId: String): Template<*>?
/**
* Clear all the templates stored in the provider.
@@ -132,6 +132,12 @@ abstract class Parameter<T>(@StringRes val name: Int,
}
}
fun release() {
lock.withLock {
observers.clear()
}
}
private fun notifyObservers() {
lock.withLock {
observers.forEach {
@@ -253,6 +253,10 @@ open class Template<R : TemplateRecipeResult>(
open val parameters: Collection<Parameter<*>>
get() = widgets.filterIsInstance<ParameterWidget<*>>().map { it.parameter }
open fun release() {
widgets.forEach { it.release() }
}
companion object {
@JvmStatic
@@ -260,11 +264,14 @@ open class Template<R : TemplateRecipeResult>(
}
}
open class ProjectTemplate(
val moduleTemplates: List<Template<*>>, @StringRes templateName: Int,
@DrawableRes thumb: Int, @StringRes description: Int?,
widgets: List<Widget<*>>, recipe: TemplateRecipe<ProjectTemplateRecipeResult>
) : Template<ProjectTemplateRecipeResult>(templateName, thumb, description, widgets, recipe) {
open class ProjectTemplate(val moduleTemplates: List<Template<*>>,
@StringRes templateName: Int,
@DrawableRes thumb: Int,
@StringRes description: Int?,
widgets: List<Widget<*>>,
recipe: TemplateRecipe<ProjectTemplateRecipeResult>
) : Template<ProjectTemplateRecipeResult>(templateName, thumb, description,
widgets, recipe) {
override val parameters: Collection<Parameter<*>>
get() = if (moduleTemplates.isEmpty()) super.parameters else super.parameters.toMutableList()
@@ -286,6 +293,11 @@ open class ProjectTemplate(
result
}
}
override fun release() {
super.release()
moduleTemplates.forEach { it.release() }
}
}
/**
@@ -293,24 +305,22 @@ open class ProjectTemplate(
*
* @property name The mdoule name (gradle format, e.g. ':app').
*/
open class ModuleTemplate(val name: String,
@StringRes
templateName: Int,
@DrawableRes
thumb: Int, @StringRes
description: Int?,
widgets: List<Widget<*>>,
recipe: TemplateRecipe<ModuleTemplateRecipeResult>
) : Template<ModuleTemplateRecipeResult>(templateName, thumb, description, widgets, recipe)
open class ModuleTemplate(val name: String, @StringRes templateName: Int,
@DrawableRes thumb: Int, @StringRes description: Int?,
widgets: List<Widget<*>>,
recipe: TemplateRecipe<ModuleTemplateRecipeResult>
) : Template<ModuleTemplateRecipeResult>(templateName, thumb, description,
widgets, recipe)
/**
* Template for creating a file.
*/
open class FileTemplate<R : FileTemplateRecipeResult>(@StringRes name: Int,
@DrawableRes thumb: Int,
@StringRes description: Int?,
widgets: List<Widget<*>>,
recipe: TemplateRecipe<R>
@DrawableRes thumb: Int,
@StringRes
description: Int?,
widgets: List<Widget<*>>,
recipe: TemplateRecipe<R>
) : Template<R>(name, thumb, description, widgets, recipe)
/**
@@ -22,12 +22,20 @@ package com.itsaky.androidide.templates
*
* Each template has a collection of widgets which is rendered when user selects a template.
*/
interface Widget<T>
interface Widget<T> {
fun release()
}
/**
* Widget for the given [parameter].
*/
sealed class ParameterWidget<T>(val parameter: Parameter<T>) : Widget<T>
sealed class ParameterWidget<T>(val parameter: Parameter<T>) : Widget<T> {
override fun release() {
parameter.release()
}
}
/**
* Widget for a [StringParameter]. Creates a text field for the parameter.
@@ -66,6 +66,7 @@ class TemplateProviderImpl : ITemplateProvider {
}
override fun clear() {
templates.forEach { it.value.release() }
templates.clear()
}
}