核心結論
Android 中子線程不依賴主線程存在。主線程 (UI 線程) 結束不會自動終止子線程。但普通 Java 線程隨進程結束而結束,長期後台任務必須依託 Service 或 WorkManager。
線程與進程關系圖譜
進程 (Process) - 資源分配單位
│
├─ 主線程 (Main/UI Thread) - 處理 UI、生命周期回調
│
├─ 子線程 (Thread/HandlerThread/RxJava/協程) - 耗時操作
│ └─ 生命周期:隨進程存續,不隨主線程銷毀
│
└─ 系統服務進程 (System Server) - 獨立進程
三種後台運行模式對比
| 模式 | 生命周期 | 適用場景 | 優先級 |
| 普通 Thread | 進程存活期間 | 短時任務 (網絡請求、文件讀寫) | 前台進程優先 |
| IntentService | 任務結束自動停止 | 串行異步任務 (已棄用,用 WorkManager) | 服務進程優先 |
| Service (前台服務) | 長期運行,通知欄常駐 | 音樂播放、定位、下載、IM 心跳 | 前台服務高優先級 |
| WorkManager | 系統調度,保證執行 | 延遲任務、周期任務、需保證執行 | 系統優化調度 |
內存洩露風險與防範
典型洩露場景
// 錯誤:匿名內部類持有外部類引用
new Thread(() -> {
while (true) {
textView.setText("更新"); // 持有 Activity 引用
Thread.sleep(1000);
}
}).start();
// Activity 銷毀後,線程仍運行,無法 GC → 內存洩露
解決方案
- 靜態內部類 + WeakReference:
static class SafeRunnable implements Runnable {
WeakReference ref;
SafeRunnable(TextView v) { ref = new WeakReference<>(v); }
public void run() {
TextView tv = ref.get();
if (tv != null) tv.post(() -> tv.setText("安全"));
}
}
- 生命周期感知組件:ViewModel + LiveData / Flow,自動處理配置變更
- 取消機制:在 onDestroy 中設置標誌位、interrupt 線程、取消協程 Job
- 使用結構化並發:Kotlin Coroutines + lifecycleScope / viewModelScope
守護線程概念澄清
- Java Daemon Thread:JVM 級概念,GC、Finalizer 等;用戶線程結束 JVM 退出,守護線程自動終止
- Android 無直接對應:Android 以進程為單位管理,無「守護線程」API
- 前台服務:通過
startForeground() 提升進程優先級,接近「守護」效果
U 盤檢測案例分析
// 系統啟動時由 init 進程啟動 usbd 服務 (獨立進程/系統服務)
// 非 App 進程,不依賴任何 Activity
// 監聽 USB 硬件中斷/內核事件
// 檢測到 U 盤 → 通過 Broadcast 通知相關 App
// 這是系統級服務,非普通 App 可實現
最佳實踐總結
- 短任務:Kotlin 協程
lifecycleScope.launch { ... } 或 RxJava
- 長任務/需保證執行:WorkManager
- 前台感知長任務:前台 Service + Notification
- 避免在線程中直接持有 View/Context 強引用
- 使用
Application Context 替代 Activity Context (如需長期持有)
理解進程 > 線程 > 組件的層級關系,是 Android 架構設計的基石。
- 上一篇文章: Android 百度地圖 SDK 初始化失敗:Application 中初始化的正確姿勢
- 下一篇文章: Java Swing 背景圖片導致 JLabel 不可見、按鈕需滑鼠懸停才顯示的排查方案
Copyright ©
程式碼之家 All Rights Reserved