Skip to main content

Debugging Applications

1. Using Logcat

Example: Basic Logcat Command

adb logcat
Option Values Description
-s tag Filter by log tag
-v brief, process, tag, thread, time, long Set log format
-t count Show last count lines
-b main, system, radio, events Select log buffer
Note: Logcat output can be filtered by log level using -v with brief or long format.

Example: Filter Logs by Tag

adb logcat -s MainActivity

Example: Set Log Level

adb logcat *:E

Common Log Levels

  • V - Verbose (lowest priority)
  • D - Debug
  • I - Info
  • W - Warning
  • E - Error
  • F - Fatal
  • S - Silent (highest priority)

2. Setting Breakpoints

Breakpoint Type Description Usage
Line Breakpoint Pauses execution at a specific line of code Right-click on the line number in the editor and select "Add Breakpoint"
Method Breakpoint Pauses execution when entering a method Right-click on the method name and select "Add Method Breakpoint"
Conditional Breakpoint Pauses only when a specified condition is met Right-click on the line number, select "More" and then "Add Conditional Breakpoint"
Field Breakpoint Pauses when a specific field is accessed or modified Right-click on the field in the debugger and select "Add Field Breakpoint"

Example: Setting a Conditional Breakpoint

fun calculateDiscount(price: Double, discountRate: Double): Double {
    val finalPrice = price * (1 - discountRate) // Set conditional breakpoint here with condition: price > 100
    return finalPrice
}
Note: Conditional breakpoints can significantly slow down execution if the condition is complex or checked frequently.

3. Inspecting Variables

Variable Type Inspection Method Description
Local Variables Debug view in IDE Visible during debug sessions, updated in real-time
Global Variables Variables tab in debugger Accessible throughout the application lifecycle
Object Properties Watch expressions Allows dynamic evaluation and inspection of object fields

Example: Watching a Variable in Kotlin

fun main() {
    val user = User("Alice", 30)
    println(user.name) // Set breakpoint here
}
Note: Use Watch expressions to inspect complex object properties or computed values during debugging sessions.
Warning: Inspecting variables in release builds may not be possible due to optimizations.

4. Using Android Debug Bridge

Command Description Usage
adb devices List connected devices adb devices
adb logcat View system logs adb logcat
adb shell Execute shell commands adb shell
adb pull Copy files from device adb pull <device_path> <local_path>
adb push Copy files to device adb push <local_path> <device_path>
adb install Install APK on device adb install <apk_file>
adb uninstall Uninstall app from device adb uninstall <package_name>

Example: View Logs

adb logcat | grep -i "myapp"</code>
</pre>
</div>
</div>
<div class="example">
<h2 id="example-install-apk">Example: Install APK<a href="#example-install-apk" class="toc__headingLink" aria-label="Link to this section"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg></a></h2>
<div class="codeBlock" data-language="bash">
<pre><code>adb install app-debug.apk</code>
</pre>
</div>
</div>
<div class="example">
<h2 id="example-pull-files">Example: Pull Files<a href="#example-pull-files" class="toc__headingLink" aria-label="Link to this section"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg></a></h2>
<div class="codeBlock" data-language="bash">
<pre><code>adb pull /sdcard/Download/myfile.txt ./</code>
</pre>
</div>
</div>
<h2 id="5-analyzing-memory-with-profiler">5. Analyzing Memory with Profiler<a href="#5-analyzing-memory-with-profiler" class="toc__headingLink" aria-label="Link to this section"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg></a></h2>
<div class="example">
<h2 id="example-memory-profiling-setup">Example: Memory Profiling Setup<a href="#example-memory-profiling-setup" class="toc__headingLink" aria-label="Link to this section"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg></a></h2>
<div class="codeBlock" data-language="kotlin"><pre><code>class MemoryProfilerActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Enable memory profiling
        val profiler = ProfilerManager.getInstance()
        profiler.startProfiling()
    }
}
Feature Description Notes
Memory Profiler Monitors heap usage, allocations, and garbage collection Available in Android Studio
Heap Dump Snapshot of all objects in memory at a specific point Use to analyze memory leaks
Allocation Tracking Tracks object creation over time Helps identify frequent allocations
Note: Memory Profiler is part of Android Studio's suite of debugging tools and requires the androidx.debug library.
Warning: Profiling can impact app performance; use in debug builds only.

Memory Profiler Capabilities

  • Real-time heap monitoring
  • Object allocation tracking
  • Garbage collection analysis
  • Memory leak detection

Steps to Analyze Memory

  1. Open Android Studio
  2. Navigate to Tools > Profiler
  3. Select your running app
  4. Click Memory tab
  5. Take heap dump or start allocation tracking

6. Monitoring Network Traffic

Example: Using OkHttp Interceptor for Logging

import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Response
import java.io.IOException

class NetworkLoggingInterceptor : Interceptor {
    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        println("Request: ${request.method} ${request.url}")
        val response = chain.proceed(request)
        println("Response: ${response.code}")
        return response
    }
}

val client = OkHttpClient.Builder()
    .addInterceptor(NetworkLoggingInterceptor())
    .build()
Feature Description Notes
OkHttp Interceptor Interceptor interface for intercepting requests and responses Useful for logging, modifying, or blocking network calls
HttpLoggingInterceptor com.squareup.okhttp3.logging.HttpLoggingInterceptor Pre-built interceptor for logging HTTP traffic

Example: Configuring HttpLoggingInterceptor

import okhttp3.logging.HttpLoggingInterceptor
import okhttp3.logging.HttpLoggingInterceptor.Level

val loggingInterceptor = HttpLoggingInterceptor().apply {
    level = Level.BODY
}

val client = OkHttpClient.Builder()
    .addInterceptor(loggingInterceptor)
    .build()

Network Monitoring Tools

  • Charles Proxy: HTTP proxy for monitoring traffic
  • Wireshark: Network protocol analyzer
  • Android Studio Profiler: Built-in tool for monitoring app performance
  • Network Inspector: In-browser dev tools (Chrome DevTools)

7. Using Layout Inspector

Example: Inspecting Layout Hierarchy

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Use Layout Inspector to analyze view hierarchy
        // Access via Android Studio: Tools > Layout Inspector
    }
}
Feature Description Usage
View Hierarchy Visual representation of all views in the layout Inspect nested views and their properties
Properties Panel Shows attributes of selected view View dimensions, margins, padding, etc.
Layout Bounds Displays actual layout bounds of views Identify layout issues or overlaps
Real-time Updates Live updates when UI changes Debug dynamic view modifications
Note: Layout Inspector works best with View and ConstraintLayout components.
Warning: Layout Inspector is not available in release builds by default.

Key Features

  • Inspect view tree structure
  • View property inspection (size, color, visibility)
  • Real-time UI modification debugging
  • Identify layout performance bottlenecks

8. Detecting ANR Issues

Issue Description Solution
ANR Application Not Responding (ANR) occurs when the main thread is blocked for more than 5 seconds Use background threads or async operations to prevent UI blocking

Example: Identifying ANR in Main Thread

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // This will cause ANR if takes more than 5 seconds
        val result = heavyComputation()
    }

    private fun heavyComputation(): String {
        Thread.sleep(10000) // Simulating long-running task
        return "Result"
    }
}
Note: ANR is detected by the system and logs an error to logcat

ANR Detection Methods

  • Monitor logcat for "ANR" messages
  • Use Android Studio's Profiler to detect UI thread blocking
  • Implement custom StrictMode for development

9. Analyzing Crash Reports

Field Description Example
crashTimestamp Time when the crash occurred 2024-05-15T14:30:45Z
exceptionType Type of exception that caused the crash java.lang.NullPointerException
stackTrace Full stack trace of the crash
at com.example.MainActivity.onCreate(MainActivity.kt:25)
at android.app.Activity.performCreate(Activity.java:7136)
deviceModel Model of the device where the crash occurred Pixel 6
osVersion Android OS version of the device 13
appVersion Version of the app at time of crash 2.1.0

Example: Parsing Crash Report

val crashReport = CrashReport.parseFromFile("crash_report.txt")
Log.d("CrashAnalyzer", "Exception: ${crashReport.exceptionType}")
Log.d("CrashAnalyzer", "Stack Trace: ${crashReport.stackTrace.joinToString("\n")}")
Note: Use tools like Firebase Crashlytics or Sentry to automatically collect and analyze crash reports in production environments.

10. Using StrictMode for Detection

Example: Enabling StrictMode

import android.os.StrictMode
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val policy = StrictMode.ThreadPolicy.Builder()
            .detectAll()
            .penaltyLog()
            .build()

        StrictMode.setThreadPolicy(policy)
    }
}
StrictMode Policy Description Notes
detectAll() Detects all potential issues Enables all checks
detectDiskReads() Detects disk reads on main thread Use for performance monitoring
detectDiskWrites() Detects disk writes on main thread Use for performance monitoring
detectNetwork() Detects network calls on main thread Use for performance monitoring
detectUnbufferedIo() Detects unbuffered I/O on main thread Use for performance monitoring
detectResourceMismatches() Detects resource mismatches Use for resource management
detectUntaggedSockets() Detects untagged socket usage Use for network security
Note: StrictMode is intended for development and debugging only. It should not be used in production builds.

Was this article helpful?