# 调试工具

## 目录
- [Logcat](#logcat)
- [Debugger](#debugger)
- [Profiler](#profiler)
- [Layout Inspector](#layout-inspector)
- [其他调试工具](#其他调试工具)
- [调试技巧](#调试技巧)
- [常见问题](#常见问题)

---

## Logcat

### Logcat简介

```java
// Logcat：Android 系统日志查看工具
// - 查看应用日志
// - 查看系统日志
// - 过滤和搜索日志
// - 保存日志文件
```

### 打开Logcat

```java
// 方式1：View → Tool Windows → Logcat
// 方式2：点击底部 Logcat 标签
// 方式3：Alt + 6（Windows/Linux）
//        Command + 6（macOS）
```

### 日志级别

```java
// 日志级别（从低到高）：
// - Verbose (V)：详细日志
// - Debug (D)：调试日志
// - Info (I)：信息日志
// - Warn (W)：警告日志
// - Error (E)：错误日志
// - Assert (A)：断言失败

Log.v(TAG, "Verbose message");
Log.d(TAG, "Debug message");
Log.i(TAG, "Info message");
Log.w(TAG, "Warning message");
Log.e(TAG, "Error message");
Log.wtf(TAG, "Assert message");
```

### 过滤日志

```java
// 1. 按包名过滤
// 在 Logcat 顶部输入：package:com.example.app

// 2. 按标签过滤
// 输入：tag:MyTag

// 3. 按级别过滤
// 选择日志级别下拉菜单

// 4. 按文本过滤
// 输入搜索关键词

// 5. 组合过滤
// package:com.example.app tag:MyTag level:error
```

### 保存日志

```java
// 1. 右键 Logcat 窗口
// 2. 选择 "Save Logcat to File"
// 3. 选择保存位置
// 4. 保存日志文件
```

### 清除日志

```java
// 点击 Logcat 工具栏的清除按钮
// 或使用快捷键：Ctrl + L（Windows/Linux）
//              Command + K（macOS）
```

---

## Debugger

### 断点调试

```java
// 1. 设置断点
// 在代码行号左侧点击，或使用 Ctrl + F8（Windows/Linux）
//                                    Command + F8（macOS）

// 2. 启动调试
// 点击调试按钮，或使用 Shift + F9

// 3. 调试操作
// - 继续执行：F9
// - 单步跳过：F8
// - 单步进入：F7
// - 单步跳出：Shift + F8
// - 停止调试：Ctrl + F2（Windows/Linux）
//            Command + F2（macOS）
```

### 断点类型

```java
// 1. 行断点（Line Breakpoint）
// 普通断点，程序执行到该行时暂停

// 2. 条件断点（Conditional Breakpoint）
// 右键断点 → 设置条件
// 例如：i > 10

// 3. 日志断点（Logpoint）
// 右键断点 → 选择 "More" → "Log evaluated expression"
// 输出日志但不暂停执行

// 4. 异常断点（Exception Breakpoint）
// Run → View Breakpoints → 添加异常断点
// 当抛出异常时暂停
```

### 调试窗口

```java
// 1. Variables（变量窗口）
// - 显示当前作用域的所有变量
// - 可以查看和修改变量值

// 2. Watches（监视窗口）
// - 添加要监视的表达式
// - 实时显示表达式值

// 3. Frames（调用栈窗口）
// - 显示方法调用栈
// - 可以跳转到任意调用栈帧

// 4. Console（控制台窗口）
// - 显示应用输出
// - 可以执行表达式
```

### 表达式求值

```java
// 在调试时：
// 1. 选择变量或表达式
// 2. 右键 → Evaluate Expression
// 3. 或使用 Alt + F8（Windows/Linux）
//        Option + F8（macOS）
// 4. 输入表达式并求值
```

---

## Profiler

### CPU Profiler

```java
// 打开 CPU Profiler：
// View → Tool Windows → Profiler
// 或 Run → Profile 'app'

// 功能：
// - 记录 CPU 使用情况
// - 分析方法调用
// - 查找性能瓶颈
// - 线程分析

// 使用步骤：
// 1. 启动应用
// 2. 点击 CPU 时间线
// 3. 选择记录方法（Sampled 或 Instrumented）
// 4. 点击 Record
// 5. 执行操作
// 6. 点击 Stop
// 7. 分析结果
```

### Memory Profiler

```java
// 打开 Memory Profiler：
// View → Tool Windows → Profiler

// 功能：
// - 查看内存使用
// - 捕获堆转储
// - 查找内存泄漏
// - 分析对象分配

// 使用步骤：
// 1. 启动应用
// 2. 点击 Memory 时间线
// 3. 执行操作
// 4. 点击 Dump Java Heap
// 5. 分析内存使用
// 6. 查找内存泄漏
```

### Network Profiler

```java
// 打开 Network Profiler：
// View → Tool Windows → Profiler

// 功能：
// - 监控网络请求
// - 查看请求详情
// - 分析网络性能
// - 查看请求时间线

// 使用步骤：
// 1. 启动应用
// 2. 点击 Network 时间线
// 3. 执行网络操作
// 4. 查看请求详情
// 5. 分析网络性能
```

### Energy Profiler

```java
// 打开 Energy Profiler：
// View → Tool Windows → Profiler

// 功能：
// - 监控电量使用
// - 分析电量消耗
// - 查找耗电问题

// 使用步骤：
// 1. 启动应用
// 2. 点击 Energy 时间线
// 3. 执行操作
// 4. 分析电量使用
```

---

## Layout Inspector

### 打开Layout Inspector

```java
// 方式1：Tools → Layout Inspector
// 方式2：View → Tool Windows → Layout Inspector

// 要求：
// - 应用必须运行在 Android 5.0+ 设备上
// - 启用 USB 调试
```

### 功能

```java
// 1. 查看视图层次
// - 显示完整的视图树
// - 可以展开和折叠节点

// 2. 查看视图属性
// - 显示所有视图属性
// - 可以查看属性值

// 3. 查看视图边界
// - 在设备上高亮显示视图
// - 查看视图位置和大小

// 4. 实时更新
// - 可以实时查看布局变化
// - 支持交互式调试
```

### 使用步骤

```java
// 1. 启动应用
// 2. 打开 Layout Inspector
// 3. 选择设备和应用进程
// 4. 点击 "Capture Layout"
// 5. 查看布局层次和属性
// 6. 点击视图节点查看属性
// 7. 在设备上高亮显示视图
```

---

## 其他调试工具

### ADB（Android Debug Bridge）

```bash
# 查看连接的设备
adb devices

# 查看日志
adb logcat

# 安装应用
adb install app.apk

# 卸载应用
adb uninstall com.example.app

# 启动Activity
adb shell am start -n com.example.app/.MainActivity

# 发送广播
adb shell am broadcast -a com.example.ACTION

# 查看应用信息
adb shell dumpsys package com.example.app

# 查看内存信息
adb shell dumpsys meminfo com.example.app
```

### StrictMode

```java
// StrictMode：检测主线程中的违规操作
// 在 Application 或 Activity 中启用

if (BuildConfig.DEBUG) {
    StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
        .detectAll()
        .penaltyLog()
        .penaltyDeath()
        .build());
    
    StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
        .detectAll()
        .penaltyLog()
        .penaltyDeath()
        .build());
}
```

### LeakCanary

```java
// LeakCanary：内存泄漏检测工具

// 1. 添加依赖
dependencies {
    debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12'
}

// 2. 自动集成（无需代码）
// LeakCanary 会自动检测内存泄漏
// 当检测到泄漏时，会显示通知
```

### Systrace

```bash
# Systrace：系统级性能分析工具

# 1. 开始跟踪
python systrace.py --time=10 -o trace.html sched freq idle am wm gfx view binder_driver hal dalvik camera input res

# 2. 在设备上执行操作
# 3. 停止跟踪
# 4. 查看 trace.html
```

### Hierarchy Viewer

```java
// Hierarchy Viewer：查看视图层次和性能
// 已弃用，推荐使用 Layout Inspector
```

### GPU Profiler

```java
// GPU Profiler：分析 GPU 性能
// 在开发者选项中启用：
// Settings → Developer Options → Profile GPU Rendering → On screen as bars
```

---

## 调试技巧

### 1. 使用日志标签

```java
// 定义日志标签
private static final String TAG = "MainActivity";

// 使用日志
Log.d(TAG, "onCreate: Activity created");
Log.d(TAG, "onCreate: savedInstanceState = " + savedInstanceState);
```

### 2. 条件断点

```java
// 设置条件断点
// 例如：只在 i > 10 时暂停
// 右键断点 → 设置条件：i > 10
```

### 3. 日志断点

```java
// 使用日志断点代替 System.out.println
// 右键断点 → More → Log evaluated expression
// 输入：i = $i, value = $value
```

### 4. 异常断点

```java
// 设置异常断点
// Run → View Breakpoints → 添加异常断点
// 选择异常类型（如 NullPointerException）
```

### 5. 远程调试

```java
// 使用 ADB 进行远程调试
// 1. 连接设备
// 2. 启用 USB 调试
// 3. 在 Android Studio 中选择设备
// 4. 启动调试
```

### 6. 多进程调试

```java
// 调试多进程应用
// 1. Run → Edit Configurations
// 2. 选择 "Debugger" 标签
// 3. 选择 "Auto" 或特定进程
```

### 7. 使用条件日志

```java
// 只在调试模式下输出日志
if (BuildConfig.DEBUG) {
    Log.d(TAG, "Debug message");
}
```

### 8. 性能分析技巧

```java
// 1. 使用 CPU Profiler 查找性能瓶颈
// 2. 使用 Memory Profiler 查找内存泄漏
// 3. 使用 Network Profiler 优化网络请求
// 4. 使用 Energy Profiler 优化电量消耗
```

---

## 常见问题

### 问题1：Logcat不显示日志

```java
// 解决方案：
// 1. 检查设备连接
// 2. 选择正确的设备和进程
// 3. 检查日志级别过滤
// 4. 清除日志并重新查看
// 5. 重启 Logcat
```

### 问题2：断点不生效

```java
// 解决方案：
// 1. 确保使用 Debug 构建变体
// 2. 检查代码是否被混淆
// 3. 重新编译项目
// 4. 检查断点是否在可执行代码行
// 5. 清除断点并重新设置
```

### 问题3：调试器无法连接

```java
// 解决方案：
// 1. 检查设备连接
// 2. 检查 USB 调试是否启用
// 3. 重启 ADB：adb kill-server && adb start-server
// 4. 检查防火墙设置
// 5. 重新连接设备
```

### 问题4：Profiler无法启动

```java
// 解决方案：
// 1. 确保设备运行 Android 5.0+
// 2. 检查应用是否正在运行
// 3. 检查设备连接
// 4. 重启 Android Studio
// 5. 检查 Profiler 插件是否启用
```

### 问题5：内存泄漏检测不准确

```java
// 解决方案：
// 1. 等待足够长时间让 GC 运行
// 2. 多次触发可能导致泄漏的操作
// 3. 使用 Memory Profiler 手动分析
// 4. 检查 LeakCanary 配置
```

---

## 调试最佳实践

### 1. 使用合适的日志级别

```java
// Verbose：详细调试信息
Log.v(TAG, "Detailed debug info");

// Debug：一般调试信息
Log.d(TAG, "Debug info");

// Info：重要信息
Log.i(TAG, "Important info");

// Warn：警告信息
Log.w(TAG, "Warning");

// Error：错误信息
Log.e(TAG, "Error", exception);
```

### 2. 避免在生产环境输出敏感信息

```java
// 使用 BuildConfig.DEBUG 控制日志输出
if (BuildConfig.DEBUG) {
    Log.d(TAG, "Sensitive info: " + sensitiveData);
}
```

### 3. 使用有意义的日志标签

```java
// 使用类名作为标签
private static final String TAG = MainActivity.class.getSimpleName();
```

### 4. 定期检查性能

```java
// 定期使用 Profiler 检查应用性能
// - CPU 使用率
// - 内存使用
// - 网络请求
// - 电量消耗
```

### 5. 使用自动化测试

```java
// 使用单元测试和集成测试
// 在 CI/CD 中自动运行测试
// 使用 Espresso 进行 UI 测试
```

---

## 总结

Android 提供了丰富的调试工具，熟练掌握这些工具可以大大提高开发效率和问题排查能力。建议：

1. 熟悉 Logcat 的使用
2. 掌握断点调试技巧
3. 定期使用 Profiler 分析性能
4. 使用 Layout Inspector 调试布局
5. 结合 ADB 进行高级调试

---

*最后更新：2024年*
