main

square/leakcanary

Last updated at: 29/12/2023 09:38

LeaksScreen.kt

TLDR

This file contains the LeaksScreen class, which is responsible for creating and managing a screen that displays information about memory leaks. The screen shows a list of leak groups, each containing details about a specific memory leak. The LeaksScreen class also handles user interactions such as clicking on a leak group to view more details.

Classes

LeaksScreen

This class represents a screen that displays information about memory leaks. It extends the Screen class and overrides the createView method to create the UI for the screen. The screen inflates a layout file (leak_canary_list.xml) and sets up a list view to display the leak groups. It also subscribes to updates from the database and refreshes the screen when changes occur. When a list item is clicked, it navigates to the LeakScreen for the selected leak group.

END

package leakcanary.internal.activity.screen

import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import android.view.ViewGroup
import android.widget.ListView
import android.widget.TextView
import com.squareup.leakcanary.core.R
import leakcanary.internal.activity.db.HeapAnalysisTable
import leakcanary.internal.activity.db.LeakTable
import leakcanary.internal.activity.db.LeakTable.AllLeaksProjection
import leakcanary.internal.activity.db.executeOnDb
import leakcanary.internal.activity.ui.SimpleListAdapter
import leakcanary.internal.activity.ui.TimeFormatter
import leakcanary.internal.navigation.NavigatingActivity
import leakcanary.internal.navigation.Screen
import leakcanary.internal.navigation.activity
import leakcanary.internal.navigation.goTo
import leakcanary.internal.navigation.inflate
import leakcanary.internal.navigation.onScreenExiting

internal class LeaksScreen : Screen() {
  override fun createView(container: ViewGroup) =
    container.inflate(R.layout.leak_canary_list).apply {

      val unsubscribeRefresh = HeapAnalysisTable.onUpdate {
        activity<NavigatingActivity>().refreshCurrentScreen()
      }

      onScreenExiting { unsubscribeRefresh() }

      executeOnDb {
        val projections = LeakTable.retrieveAllLeaks(db)
        updateUi { onGroupsRetrieved(projections) }
      }
    }

  private fun View.onGroupsRetrieved(projections: List<AllLeaksProjection>) {
    activity.title = resources.getQuantityString(
      R.plurals.leak_canary_distinct_leaks,
      projections.size, projections.size
    )

    val listView = findViewById<ListView>(R.id.leak_canary_list)

    listView.adapter =
      SimpleListAdapter(R.layout.leak_canary_leak_row, projections) { view, position ->
        val countView = view.findViewById<TextView>(R.id.leak_canary_count_text)
        val descriptionView = view.findViewById<TextView>(R.id.leak_canary_leak_text)
        val timeView = view.findViewById<TextView>(R.id.leak_canary_time_text)
        val newChipView = view.findViewById<TextView>(R.id.leak_canary_chip_new)
        val libraryLeakChipView = view.findViewById<TextView>(R.id.leak_canary_chip_library_leak)

        val projection = projections[position]
        countView.isEnabled = projection.isNew

        newChipView.visibility = if (projection.isNew) VISIBLE else GONE
        libraryLeakChipView.visibility = if (projection.isLibraryLeak) VISIBLE else GONE

        countView.text = projection.leakTraceCount.toString()
        descriptionView.text = projection.shortDescription

        val formattedDate =
          TimeFormatter.formatTimestamp(view.context, projection.createdAtTimeMillis)
        timeView.text =
          resources.getString(R.string.leak_canary_group_list_time_label, formattedDate)
      }

    listView.setOnItemClickListener { _, _, position, _ ->
      goTo(LeakScreen(projections[position].signature))
    }
  }
}