初學 Android 時最容易混淆的概念之一:super.onCreate() 與 setContentView() 似乎都在「畫介面」,到底誰負責什麼?為什麼順序不能顛倒?本文從原始碼、生命週期、View 繪製流程三個層次徹底釐清。
super.onCreate():初始化 Activity 運行環境(Context、Window、FragmentManager 等)
setContentView():解析 XML 佈局、建立 View 階層、掛載到 Window
// Activity.java (簡化)
protected void onCreate(@Nullable Bundle savedInstanceState) {
mCalled = true; // 標記子類已調用 super.onCreate()
// 1. 恢復 Fragment 狀態
if (mFragmentManager != null) mFragmentManager.noteStateNotSaved();
// 2. 初始化 Window(關鍵:getWindow() 會創建 PhoneWindow)
// 3. 設置預設主題、標題欄等
}
super.onCreate() **必須最先呼叫**,因為子類後續操作(如 findViewById、setContentView)依賴父類建立的 Window、Context、FragmentManager 等核心設施。
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID); // 委託給 Window
initViewTreeOwners(); // 初始化 ViewTreeLifecycleOwner 等現代架構組件
}
public void setContentView(int layoutResID) {
// 1. 若無 DecorView 則創建(DecorView 是整個視圖樹的根容器)
// 2. LayoutInflater.from(context).inflate(layoutResID, mContentParent)
// → 解析 XML → 建立 View 階層 → 加入到 mContentParent (通常是 FrameLayout)
// 3. 觸發 onContentChanged() 回調
}
| 錯誤順序 | 後果 |
|---|---|
| 先 setContentView,後 super.onCreate() | getWindow() 返回 null → NullPointerException;FragmentManager 未初始化 → Fragment 操作崩潰 |
| super.onCreate() 中使用 findViewById | View 尚未建立 → 返回 null |
View/ViewGroup 物件樹。DecorView 是 FrameLayout,包含標題欄區域與內容區域 android.R.id.content。ViewRootImpl.performTraversals() 驅動三大流程,最終在 Canvas 上繪製像素。findViewById、綁定事件(但通常直接寫在 onCreate setContentView 之後即可)。setContentView(R.layout.main); super.onCreate(savedInstanceState); → **崩潰**。onCreate 中大量耗時操作(IO、網路)→ **ANR**。應放入 ViewModel + Coroutine/RxJava。setContentView 後立即 findViewById / Binding 初始化。ViewBinding 或 DataBinding 替代 findViewById,編譯期型別安全。androidx.activity.viewTree 觀察 View 生命週期。若需根據條件載入不同佈局:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int layoutRes = isTablet() ? R.layout.activity_main_tablet : R.layout.activity_main_phone;
setContentView(layoutRes);
// 後續邏輯統一處理,findViewById 需注意 ID 是否存在於當前佈局
}
或使用 Fragment + FragmentContainerView 實現更靈活的動態 UI 組合。
super.onCreate() 鋪設「舞臺」(Context、Window、FragmentManager),setContentView() 搭建「佈景」(View 階層)。二者分工明確、順序固定、缺一不可。理解這層關係,即可避開 90% 的生命週期初始化坑,寫出穩健的 Android 元件。