Skip to content
This repository was archived by the owner on Oct 18, 2024. It is now read-only.

Commit 0801e90

Browse files
committed
fix: gracefully handle activity destroyed state in EditorBuildEventListener (fixes #1688, fixes #1748)
1 parent c894d3d commit 0801e90

File tree

3 files changed

+61
-22
lines changed

3 files changed

+61
-22
lines changed

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

+9-3
Original file line numberDiff line numberDiff line change
@@ -204,9 +204,15 @@ abstract class ProjectHandlerActivity : BaseEditorActivity() {
204204
} catch (err: Throwable) {
205205
log.error("Unable to unbind service")
206206
} finally {
207-
(Lookup.getDefault().lookup(BuildService.KEY_BUILD_SERVICE) as? GradleBuildService?)
208-
?.setEventListener(null)
209-
Lookup.getDefault().unregister(BuildService.KEY_BUILD_SERVICE)
207+
Lookup.getDefault().apply {
208+
209+
(lookup(BuildService.KEY_BUILD_SERVICE) as? GradleBuildService?)
210+
?.setEventListener(null)
211+
212+
unregister(BuildService.KEY_BUILD_SERVICE)
213+
}
214+
215+
mBuildEventListener.release()
210216
editorViewModel.isBoundToBuildSerice = false
211217
}
212218
}

app/src/main/java/com/itsaky/androidide/handlers/EditorBuildEventListener.kt

+51-18
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import com.itsaky.androidide.tooling.api.messages.result.BuildInfo
2626
import com.itsaky.androidide.tooling.events.ProgressEvent
2727
import com.itsaky.androidide.tooling.events.configuration.ProjectConfigurationStartEvent
2828
import com.itsaky.androidide.tooling.events.task.TaskStartEvent
29+
import com.itsaky.androidide.utils.ILogger
2930
import com.itsaky.androidide.utils.flashError
3031
import com.itsaky.androidide.utils.flashSuccess
3132
import java.lang.ref.WeakReference
@@ -36,77 +37,109 @@ import java.lang.ref.WeakReference
3637
*/
3738
class EditorBuildEventListener : GradleBuildService.EventListener {
3839

40+
private var enabled = true
3941
private var activityReference: WeakReference<EditorHandlerActivity> = WeakReference(null)
4042

43+
companion object {
44+
45+
private val log = ILogger.newInstance("EditorBuildEventListener")
46+
}
47+
48+
private val _activity: EditorHandlerActivity?
49+
get() = activityReference.get()
50+
private val activity: EditorHandlerActivity
51+
get() = checkNotNull(activityReference.get()) { "Activity reference has been destroyed!" }
52+
4153
fun setActivity(activity: EditorHandlerActivity) {
4254
this.activityReference = WeakReference(activity)
55+
this.enabled = true
56+
}
57+
58+
fun release() {
59+
activityReference.clear()
60+
this.enabled = false
4361
}
4462

4563
override fun prepareBuild(buildInfo: BuildInfo) {
64+
checkActivity("prepareBuild") ?: return
65+
4666
val isFirstBuild = isFirstBuild
47-
activity()
67+
activity
4868
.setStatus(
49-
activity().getString(if (isFirstBuild) string.preparing_first else string.preparing)
69+
activity.getString(if (isFirstBuild) string.preparing_first else string.preparing)
5070
)
5171

5272
if (isFirstBuild) {
53-
activity().showFirstBuildNotice()
73+
activity.showFirstBuildNotice()
5474
}
5575

56-
activity().editorViewModel.isBuildInProgress = true
57-
activity().binding.bottomSheet.clearBuildOutput()
76+
activity.editorViewModel.isBuildInProgress = true
77+
activity.binding.bottomSheet.clearBuildOutput()
5878

5979
if (buildInfo.tasks.isNotEmpty()) {
60-
activity().binding.bottomSheet.appendBuildOut(
61-
activity().getString(R.string.title_run_tasks) + " : " + buildInfo.tasks)
80+
activity.binding.bottomSheet.appendBuildOut(
81+
activity.getString(R.string.title_run_tasks) + " : " + buildInfo.tasks)
6282
}
6383
}
6484

6585
override fun onBuildSuccessful(tasks: List<String?>) {
86+
checkActivity("onBuildSuccessful") ?: return
87+
6688
analyzeCurrentFile()
6789

6890
isFirstBuild = false
69-
activity().editorViewModel.isBuildInProgress = false
91+
activity.editorViewModel.isBuildInProgress = false
7092

71-
activity().flashSuccess(R.string.build_status_sucess)
93+
activity.flashSuccess(R.string.build_status_sucess)
7294
}
7395

7496
override fun onProgressEvent(event: ProgressEvent) {
97+
checkActivity("onProgressEvent") ?: return
98+
7599
if (event is ProjectConfigurationStartEvent || event is TaskStartEvent) {
76-
activity().setStatus(event.descriptor.displayName)
100+
activity.setStatus(event.descriptor.displayName)
77101
}
78102
}
79103

80104
override fun onBuildFailed(tasks: List<String?>) {
105+
checkActivity("onBuildFailed") ?: return
81106

82107
analyzeCurrentFile()
83108

84109
isFirstBuild = false
85-
activity().editorViewModel.isBuildInProgress = false
110+
activity.editorViewModel.isBuildInProgress = false
86111

87-
activity().flashError(R.string.build_status_failed)
112+
activity.flashError(R.string.build_status_failed)
88113
}
89114

90115
override fun onOutput(line: String?) {
116+
checkActivity("onOutput") ?: return
91117

92-
line?.let { activity().appendBuildOutput(it) }
118+
line?.let { activity.appendBuildOutput(it) }
93119
// TODO This can be handled better when ProgressEvents are received from Tooling API server
94120
if (line!!.contains("BUILD SUCCESSFUL") || line.contains("BUILD FAILED")) {
95-
activity().setStatus(line)
121+
activity.setStatus(line)
96122
}
97123
}
98124

99125
private fun analyzeCurrentFile() {
126+
checkActivity("analyzeCurrentFile") ?: return
100127

101-
val editorView = activity().getCurrentEditor()
128+
val editorView = _activity?.getCurrentEditor()
102129
if (editorView != null) {
103130
val editor = editorView.editor
104131
editor?.analyze()
105132
}
106133
}
107134

108-
fun activity(): EditorHandlerActivity {
109-
return activityReference.get()
110-
?: throw IllegalStateException("Activity reference has been destroyed!")
135+
private fun checkActivity(action: String): EditorHandlerActivity? {
136+
if (!enabled) return null
137+
138+
return _activity.also {
139+
if (it == null) {
140+
log.warn("[$action] Activity reference has been destroyed!")
141+
enabled = false
142+
}
143+
}
111144
}
112145
}

templates-impl/src/main/java/com/itsaky/androidide/templates/impl/ConstraintVerifier.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ object ConstraintVerifier {
5757
* @return The error message if the validation fails, `null` otherwise.
5858
*/
5959
fun verify(input: String, constraints: List<ParameterConstraint>): String? {
60-
var err: String? = null
60+
var err: String?
6161
for (constraint in constraints) {
6262
err = when (constraint) {
6363
NONEMPTY -> checkNotEmpty(input)

0 commit comments

Comments
 (0)