在使用 FragmentTabHost 載入多個包含 ListView 或 ViewPager 的 Fragment 時,若用戶快速按下返回鍵銷毀 Activity,應用會拋出 NullPointerException,錯誤指向 Adapter 使用 Context 為 null 的位置。
Fragment 的生命週期與 Activity 綁定。當 Activity 被銷毀,Fragment 可能尚未完全分離,但其 getActivity() 已返回 null。此時若異步任務(如數據加載完成回調)仍嘗試訪問 Context 或更新 UI,即會導致崩潰。
在 Fragment 中執行 UI 操作前,務必驗證其是否仍依附於 Activity:
/**
* 判斷當前 Fragment 是否仍與 Activity 關聯
* @return true 表示安全,可繼續操作;false 應立即返回
*/
public boolean hasExist() {
return isAdded() && !isDetached();
}
// 在異步回調或數據加載完成後更新 UI 前
if (!hasExist()) {
return; // Fragment 已分離,放棄操作
}
// 安全訪問 Context、更新 Adapter 等
adapter.notifyDataSetChanged();
在 onDetach() 或 onDestroy() 中取消網絡請求、資料庫查詢等:
@Override
public void onDetach() {
super.onDetach();
if (disposable != null && !disposable.isDisposed()) {
disposable.dispose(); // RxJava 示例
}
}
採用 Android Jetpack ViewModel 與 LiveData,自動處理生命週期,避免手動管理:
// ViewModel 中持有數據,不持有 Context 引用
public class MyViewModel extends ViewModel {
private MutableLiveData> data = new MutableLiveData<>();
// ...
}
// Fragment 中觀察數據,自動處理生命週期
viewModel.getData().observe(getViewLifecycleOwner(), items -> {
adapter.submitList(items);
});
若必須在 Activity 狀態保存後操作 Fragment,使用 commitAllowingStateLoss() 但需謹慎,優先重構邏輯避免此情況。
Fragment 管理的核心原則是 「操作前檢查依附狀態,銷毀時清理資源」。結合 isAdded()、isDetached() 檢查,並遷移至 ViewModel/LiveData 架構,可徹底解決 Activity 銷毀導致的 Fragment 崩潰問題。