Debugger and Inspector

Breakpoints, the Debugger and Compose Layout Inspector

A debuggable app's runtime speaks the Java Debug Wire Protocol (JDWP). Studio's debugger forwards a local port to it; so can you, and the JDK's command-line jdb then sets breakpoints as the Studio gutter does. am start -D holds the app at launch until a debugger attaches:

A breakpoint in CatalogViewModel.refresh(), from the command lineShell
adb shell am start -D -n com.example.booknest/.MainActivity
adb forward tcp:8716 jdwp:$(adb shell pidof -s com.example.booknest)
jdb -attach localhost:8716
> stop in com.example.booknest.ui.CatalogViewModel.refresh
> cont
Output
Breakpoint hit: "thread=main", com.example.booknest.ui.CatalogViewModel.refresh(), line=51
  bci=0
main[1] where
  [1] com.example.booknest.ui.CatalogViewModel.refresh (ViewModels.kt:51)
  [2] com.example.booknest.ui.CatalogViewModel.<init> (ViewModels.kt:47)
...
  [14] com.example.booknest.ui.CatalogRouteKt.CatalogRoute (ViewModel.kt:65)
...
  [168] com.android.internal.os.ZygoteInit.main (ZygoteInit.java:932)
main[1] print this.load.getValue()
 this.load.getValue() = "Loading"

Read bottom-up, the 168 frames run from the zygote through a Choreographer frame, Compose 234 measuring the Scaffold and hiltViewModel() in CatalogRoute to Hilt's factory and the constructor. Studio's Debug window shows the same frames over the same protocol.

Layout Inspector shows the running Compose hierarchy with each node's parameters and semantics, and, for API 29+ and Compose 1.2+, how often each composable recomposed and was skipped. Recomposition Counts reproduces those counts in logcat.