HeapAnalysisFailureScreen.kt
TLDR
This file defines the HeapAnalysisFailureScreen
class, which is responsible for displaying details of a heap analysis failure on the UI. It retrieves the analysis information from the database and updates the UI accordingly. It also provides options to retry the analysis, file a bug report, share the heap dump file, and delete the analysis.
Classes
HeapAnalysisFailureScreen
This class represents a screen that displays the details of a heap analysis failure. It extends the Screen
class. The main functionality of this class is to retrieve the heap analysis information from the database and update the UI accordingly. It also handles options related to retry the analysis, file a bug report, share the heap dump file, and delete the analysis.
The HeapAnalysisFailureScreen
class has the following methods:
-
createView(container: ViewGroup)
: Creates the view for the screen by inflating the corresponding layout file and setting up the UI elements. It sets the screen title and retrieves the heap analysis information from the database. If the analysis is deleted, it displays a message. Otherwise, it calls theonFailureRetrieved
method to update the UI with the analysis details. -
onFailureRetrieved(heapAnalysis: HeapAnalysisFailure, heapDumpFileExist: Boolean)
: Updates the UI with the heap analysis details. It sets the screen title, constructs the failure text with HTML links, handles the URL actions, and sets the text and click listeners for the relevant UI elements. It also handles the options menu, allowing the user to delete the analysis if they are not a monkey user.
package leakcanary.internal.activity.screen
import android.app.ActivityManager
import android.text.Html
import android.text.SpannableStringBuilder
import android.text.method.LinkMovementMethod
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import com.squareup.leakcanary.core.R
import java.util.UUID
import leakcanary.EventListener.Event.HeapDump
import leakcanary.internal.InternalLeakCanary
import leakcanary.internal.activity.db.HeapAnalysisTable
import leakcanary.internal.activity.db.executeOnDb
import leakcanary.internal.activity.shareHeapDump
import leakcanary.internal.activity.shareToGitHubIssue
import leakcanary.internal.activity.ui.UiUtils
import leakcanary.internal.navigation.Screen
import leakcanary.internal.navigation.activity
import leakcanary.internal.navigation.goBack
import leakcanary.internal.navigation.inflate
import leakcanary.internal.navigation.onCreateOptionsMenu
import shark.HeapAnalysisFailure
internal class HeapAnalysisFailureScreen(
private val analysisId: Long
) : Screen() {
override fun createView(container: ViewGroup) =
container.inflate(R.layout.leak_canary_heap_analysis_failure_screen).apply {
activity.title = resources.getString(R.string.leak_canary_loading_title)
executeOnDb {
val heapAnalysis = HeapAnalysisTable.retrieve<HeapAnalysisFailure>(db, analysisId)
if (heapAnalysis == null) {
updateUi {
activity.title = resources.getString(R.string.leak_canary_analysis_deleted_title)
}
} else {
val heapDumpFileExist = heapAnalysis.heapDumpFile.exists()
updateUi { onFailureRetrieved(heapAnalysis, heapDumpFileExist) }
}
}
}
private fun View.onFailureRetrieved(
heapAnalysis: HeapAnalysisFailure,
heapDumpFileExist: Boolean
) {
activity.title = resources.getString(R.string.leak_canary_analysis_failed)
val failureText =
if (heapDumpFileExist) {
"You can <a href=\"try_again\">run the analysis again</a>.<br><br>"
} else {
""
} + """
Please <a href="file_issue">click here</a> to file a bug report.
The stacktrace details will be copied into the clipboard and you just need to paste into the
GitHub issue description.""" + (if (heapDumpFileExist) {
"""
<br><br>To help reproduce the issue, please share the
<a href="share_hprof">Heap Dump file</a> and upload it to the GitHub issue.
"""
} else "")
val failure = Html.fromHtml(failureText) as SpannableStringBuilder
UiUtils.replaceUrlSpanWithAction(failure) { urlSpan ->
when (urlSpan) {
"file_issue" -> {
{
shareToGitHubIssue(heapAnalysis)
}
}
"share_hprof" -> {
{
shareHeapDump(heapAnalysis.heapDumpFile)
}
}
"try_again" -> {
{
InternalLeakCanary.sendEvent(
HeapDump(
uniqueId = UUID.randomUUID().toString(),
file = heapAnalysis.heapDumpFile,
durationMillis = heapAnalysis.dumpDurationMillis,
reason = "Retrying heap analysis after failure."
)
)
}
}
else -> null
}
}
findViewById<TextView>(R.id.leak_canary_header_text).apply {
movementMethod = LinkMovementMethod.getInstance()
text = failure
}
findViewById<TextView>(R.id.leak_canary_stacktrace).text = heapAnalysis.exception.toString()
onCreateOptionsMenu { menu ->
if (!ActivityManager.isUserAMonkey()) {
menu.add(R.string.leak_canary_delete)
.setOnMenuItemClickListener {
executeOnDb {
HeapAnalysisTable.delete(db, analysisId, heapAnalysis.heapDumpFile)
updateUi {
goBack()
}
}
true
}
}
}
}
}