Debugging Applications
1. Using 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.Common Log Levels
V- Verbose (lowest priority)D- DebugI- InfoW- WarningE- ErrorF- FatalS- 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
- Open Android Studio
- Navigate to
Tools > Profiler - Select your running app
- Click
Memorytab - 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
Profilerto detect UI thread blocking - Implement custom
StrictModefor 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 | |
| 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.