CPS251 Android Development by Scott Shaper

Android Diagnostics

When your app isn't working as expected, Android Studio provides powerful tools to help you find and fix problems. This guide will show you how to use these tools effectively to debug your Compose applications.

Debug Mode

Debug mode is your primary tool for investigating how your app behaves at runtime. It allows you to pause execution, inspect variables, and step through your code line by line.

Opening the Debug Window

To open the debug window in Android Studio:

The debug window appears at the bottom of Android Studio and shows:

Setting Up Debug Mode

To start debugging:

  1. Select your target device or emulator
  2. Click the debug icon (bug) in the toolbar or press Shift+F9
  3. Wait for the app to build and launch in debug mode

Using Breakpoints

Breakpoints are markers that tell Android Studio to pause execution at specific points in your code:

@Composable
fun MyScreen() {
    var count by remember { mutableStateOf(0) }
    
    Button(onClick = { 
        count++  // Set a breakpoint here to inspect 'count'
    }) {
        Text("Count: $count")
    }
}

When execution pauses at a breakpoint, you can:

Conditional Breakpoints

Sometimes you only want to pause when specific conditions are met:

@Composable
fun UserList(users: List) {
    LazyColumn {
        items(users) { user ->
            // Breakpoint with condition: user.age > 18
            UserCard(user)
        }
    }
}

Layout Inspector

The Layout Inspector is a visual tool that shows you exactly how your UI is structured and rendered. It's particularly useful for debugging layout issues in Compose.

Accessing the Layout Inspector

  1. Select your target device or emulator
  2. Run your app in debug mode
  3. Click Tools → Layout Inspector
  4. Or you can click the icon with the magnifying glass over teh boxes in the upper left corner of your emulator screen

Key Features

Common Uses

The Layout Inspector helps you:

Logcat

Logcat is Android's logging system that provides detailed information about your app's behavior, system events, and error messages.

Understanding Log Levels

Android uses different log levels to indicate the importance of messages:

Using Logcat in Your Code

Add logging statements to your code:

import android.util.Log

@Composable
fun MyScreen() {
    val scope = rememberCoroutineScope()
    
    LaunchedEffect(Unit) {
        try {
            Log.d("MyScreen", "Starting data fetch")
            val data = fetchData()
            Log.i("MyScreen", "Data fetched successfully: $data")
        } catch (e: Exception) {
            Log.e("MyScreen", "Error fetching data", e)
        }
    }
}

Filtering Logs

Effective log filtering is crucial for finding relevant information:

Best Practices

To make the most of these debugging tools:

Common Debugging Scenarios

Here are some typical problems and how to solve them:

UI Not Updating

If your UI isn't updating as expected:

  1. Check the Layout Inspector to verify component properties
  2. Add breakpoints in your state management code
  3. Look for recomposition logs in Logcat

App Crashes

When your app crashes:

  1. Check Logcat for the stack trace
  2. Set breakpoints before the crash point
  3. Inspect variable values leading up to the crash

Performance Issues

For performance problems:

  1. Use the Layout Inspector to check for unnecessary recompositions
  2. Monitor Logcat for performance-related warnings
  3. Profile your app using Android Studio's profiler tools

Remember: Effective debugging is a skill that improves with practice. The more you use these tools, the better you'll become at quickly identifying and fixing issues in your apps.