- 這是 Android 10 源碼分析系列的第 6 篇
- 分支:android-10.0.0_r14
- 全文閱讀大概 10 分鐘
經過這篇文章你將學習到如下內容,將在文末總結部分會給出相應的答案html
本文主要分析 Activity、Window、PhoneWindow、WindowManager 之間的關係,爲咱們後面的文章 「如何在 Andorid 系統裏添加自定義View」 等等文章奠基基礎,先來了解一下它們的基本概念java
在分析他們以前的關係以前,咱們先來回顧一下 Acivity 和 Dialog 視圖解析綁定的過程android
Acivity 和 Dialog 相關的文章:算法
在以前的文章 分別介紹了 Acivity 和 自定義 Dialog 視圖的解析和綁定,總的來講分爲三步編程
LayoutInflater 的 inflate 方法有多個重載的方法,經常使用的是下面三個參數的方法
frameworks/base/core/java/android/view/LayoutInflater.java設計模式
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}
複製代碼
resource 其實很好理解就是資源 Id,而 root 和 attachToRoot 分別表明什麼意思:bash
當 View 解析完成以後,最後會調用 WindowManager 的 addView 方法,WindowManager 是一個接口類,繼承自接口 ViewManager,用來管理 Window,它的實現類爲 WindowManagerImpl,因此調用 WindowManager 的 addView 方法,實際上調用的是 WindowManagerImpl 的 addView 方法
frameworks/base/core/java/android/view/WindowManagerImpl.javaapp
public final class WindowManagerImpl implements WindowManager {
@UnsupportedAppUsage
// 單例的設計模式
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
private final Context mContext;
private final Window mParentWindow;
......
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
// mGlobal 是 WindowManagerGlobal 的實例
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
......
}
複製代碼
mGlobal 是 WindowManagerGlobal 的實例,使用的單例設計模式,參數 mParentWindow 是 Window 的實例,其實是委託給 WindowManagerGlobal 去實現的
ide
到這裏咱們關於 Acivity 和 Dialog 視圖的解析和添加過程大概介紹完了,關於 Dialog 的視圖如何與 Window 綁定在 0xA05 Android 10 源碼分析:Dialog 加載繪製流程以及在 Kotlin、DataBinding 中的使用 文章中介紹了,接下來分析一下 Activity、Window、WindowManager 的關係工具
在 Activity 內部維護着一個 Window 的實例變量 mWindow
frameworks/base/core/java/android/app/Activity.java
public class Activity extends ContextThemeWrappe{
private Window mWindow;
}
複製代碼
Window 是一個抽象類,它的具體實現類爲 PhoneWindow,在 Activity 的 attach 方法中給 Window 的實例變量 mWindow 賦值
frameworks/base/core/java/android/app/Activity.java
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
......
mWindow = new PhoneWindow(this, window, activityConfigCallback);
......
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
......
}
複製代碼
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
......
// mWindowManager 是 WindowManagerImpl的實例變量
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
複製代碼
將 WindowManager 轉換爲 WindowManagerImpl,以後調用 createLocalWindowManager 方法,並傳遞當前的 Window 對象,構建 WindowManagerImpl 對象,以後賦值給 mWindowManager
frameworks/base/core/java/android/view/WindowManagerImpl.java
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mContext, parentWindow);
}
複製代碼
其實在 createLocalWindowManager 方法中,就作了一件事,將 Window 做爲參數構建了一個 WindowManagerImpl 對象返還給調用處
總的來講,其實就是在 Activity 的 attach 方法中,經過調用 Window 的 setWindowManager 方法將 Window 和 WindowManager 關聯在了一塊兒
PhoneWindow 是 Window 的實現類,它是一個窗口,自己並不具有 View 相關的能力,實際上在 PhoneWindow 內部維護這一個變量 mDecor
frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java
public class PhoneWindow extends Window{
// This is the top-level view of the window, containing the window decor.
private DecorView mDecor;
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
// 完成DecorView的實例化
mDecor = generateDecor(-1);
......
}
if (mContentParent == null) {
// 調用 generateLayout 方法 要負責了DecorView的初始設置,諸如主題相關的feature、DecorView的背景
mContentParent = generateLayout(mDecor);
}
......
}
// 完成DecorView的實例化
protected DecorView generateDecor(int featureId) {
......
return new DecorView(context, featureId, this, getAttributes());
}
// 調用 generateLayout 方法 要負責了DecorView的初始設置,
// 諸如主題相關的feature、DecorView的背景,同時也初始化 contentParent
protected ViewGroup generateLayout(DecorView decor) {
......
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
......
}
}
複製代碼
當 View 初始化完成以後,最後會進入 ActivityThread 的 handlerResumeActivity 方法,執行 執行了r.activity.makeVisible()方法
frameworks/base/core/java/android/app/ActivityThread.java
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
......
if (r.activity.mVisibleFromClient) {
r.activity.makeVisible();
}
......
}
複製代碼
最終調用 Activity 的 makeVisible 方法,把 decorView 添加到 WindowManage 中
frameworks/base/core/java/android/app/Activity.java
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
複製代碼
到這裏他們之間的關係明確了:
public class Activity extends ContextThemeWrappe{
private Window mWindow;
}
複製代碼
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
複製代碼
在 Activity 的 attach 方法中,調用 PhoneWindow 的 setWindowManager 方法,這個方法的具體實現發生在 Window 中,最終調用的是 Window 的 setWindowManager 方法,將 Window 和 WindowManager 關聯在了一塊兒
frameworks/base/core/java/android/view/Window.java
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
......
// mWindowManager 是 WindowManagerImpl的實例變量
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
複製代碼
Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
...
// 獲取WindowManager對象
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
// 構建PhoneWindow
final Window w = new PhoneWindow(mContext);
// mWindow 是PhoneWindow實例
mWindow = w;
...
}
複製代碼
public void show() {
// 獲取DecorView
mDecor = mWindow.getDecorView();
// 獲取佈局參數
WindowManager.LayoutParams l = mWindow.getAttributes();
// 將DecorView和佈局參數添加到WindowManager中
mWindowManager.addView(mDecor, l);
}
複製代碼
致力於分享一系列 Android 系統源碼、逆向分析、算法相關的文章,每篇文章都會反覆推敲,若是你同我同樣喜歡 coding,一塊兒來學習,期待與你一塊兒成長