#### 8.3.1 Activity的Window創建過程
要分析Activity中的Window的創建過程就必須了解Activity的啟動過程,詳細的過程會在第9章進行介紹,這里先大概了解即可。Activity的啟動過程很復雜,最終會由ActivityThread中的performLaunchActivity()來完成整個啟動過程,在這個方法內部會通過類加載器創建Activity的實例對象,并調用其attach方法為其關聯運行過程中所依賴的一系列上下文環境變量,代碼如下所示。
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
...
if (activity ! = null) {
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackage-
Manager());
Configuration config = new Configuration(mCompatConfiguration);
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.voiceInteractor);
...
}
在Activity的attach方法里,系統會創建Activity所屬的Window對象并為其設置回調接口,Window對象的創建是通過PolicyManager的makeNewWindow方法實現的。由于Activity實現了Window的Callback接口,因此當Window接收到外界的狀態改變時就會回調Activity的方法。Callback接口中的方法很多,但是有幾個卻是我們都非常熟悉的,比如onAttachedToWindow、onDetachedFromWindow、dispatchTouchEvent,等等,代碼如下所示。
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode ! = WindowManager.LayoutParams.SOFT_INPUT_STATE_
UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions ! = 0) {
mWindow.setUiOptions(info.uiOptions);
}
從上面的分析可以看出,Activity的Window是通過PolicyManager的一個工廠方法來創建的,但是從PolicyManager的類名可以看出,它不是一個普通的類,它是一個策略類。PolicyManager中實現的幾個工廠方法全部在策略接口IPolicy中聲明了,IPolicy的定義如下:
public interface IPolicy {
public Window makeNewWindow(Context context);
public LayoutInflater makeNewLayoutInflater(Context context);
public WindowManagerPolicy makeNewWindowManager();
public FallbackEventHandler makeNewFallbackEventHandler(Context
context);
}
在實際的調用中,PolicyManager的真正實現是Policy類,Policy類中的makeNewWindow方法的實現如下,由此可以發現,Window的具體實現的確是PhoneWindow。
public Window makeNewWindow(Context context) {
return new PhoneWindow(context);
}
關于策略類PolicyManager是如何關聯到Policy上面的,這個無法從源碼中的調用關系來得出,這里猜測可能是由編譯環節動態控制的。到這里Window已經創建完成了,下面分析Activity的視圖是怎么附屬在Window上的。由于Activity的視圖由setContentView方法提供,我們只需要看setContentView方法的實現即可。
public void setContentView(int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
從Activity的setContentView的實現可以看出,Activity將具體實現交給了Window處理,而Window的具體實現是PhoneWindow,所以只需要看PhoneWindow的相關邏輯即可。PhoneWindow的setContentView方法大致遵循如下幾個步驟。
* 1.如果沒有DecorView,那么就創建它
DecorView是一個FrameLayout,在第4章已經做了初步的介紹,這里再簡單說一下。DecorView是Activity中的頂級View,一般來說它的內部包含標題欄和內部欄,但是這個會隨著主題的變換而發生改變。不管怎么樣,內容欄是一定要存在的,并且內容來具體固定的id,那就是“content”,它的完整id是android.R.id.content。DecorView的創建過程由installDecor方法來完成,在方法內部會通過generateDecor方法來直接創建DecorView,這個時候DecorView還只是一個空白的FrameLayout:
protected DecorView generateDecor() {
return new DecorView(getContext(), -1);
}
為了初始化DecorView的結構,PhoneWindow還需要通過generateLayout方法來加載具體的布局文件到DecorView中,具體的布局文件和系統版本以及主題有關,這個過程如下所示。
View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
mContentRoot = (ViewGroup) in;
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
其中ID_ANDROID_CONTENT的定義如下,這個id所對應的ViewGroup就是mContentParent:
public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.
content
* 2.將View添加到DecorView的mContentParent中
這個過程就比較簡單了,由于在步驟1中已經創建并初始化了DecorView,因此這一步直接將Activity的視圖添加到DecorView的mContentParent中即可:mLayoutInflater. inflate(layoutResID, mContentParent)。到此為止,Activity的布局文件已經添加到DecorView里面了,由此可以理解Activity的setContentView這個方法的來歷了。不知道讀者是否曾經懷疑過:為什么不叫setView呢?它明明是給Activity設置視圖的啊!從這里來看,它的確不適合叫setView,因為Activity的布局文件只是被添加到DecorView的mContentParent中,因此叫setContentView更加準確。
* 3.回調Activity的onContentChanged方法通知Activity視圖已經發生改變
這個過程就更簡單了,由于Activity實現了Window的Callback接口,這里表示Activity的布局文件已經被添加到DecorView的mContentParent中了,于是需要通知Activity,使其可以做相應的處理。Activity的onContentChanged方法是個空實現,我們可以在子Activity中處理這個回調。這個過程的代碼如下所示。
final Callback cb = getCallback();
if (cb ! = null && ! isDestroyed()) {
cb.onContentChanged();
}
經過了上面的三個步驟,到這里為止DecorView已經被創建并初始化完畢,Activity的布局文件也已經成功添加到了DecorView的mContentParent中,但是這個時候DecorView還沒有被WindowManager正式添加到Window中。這里需要正確理解Window的概念,Window更多表示的是一種抽象的功能集合,雖然說早在Activity的attach方法中Window就已經被創建了,但是這個時候由于DecorView并沒有被WindowManager識別,所以這個時候的Window無法提供具體功能,因為它還無法接收外界的輸入信息。在ActivityThread的handleResumeActivity方法中,首先會調用Activity的onResume方法,接著會調用Activity的makeVisible(),正是在makeVisible方法中,DecorView真正地完成了添加和顯示這兩個過程,到這里Activity的視圖才能被用戶看到,如下所示。
void makeVisible() {
if (! mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
到這里,Activity中的Window的創建過程已經分析完了,讀者對整個過程是不是有了更進一步的理解了呢?
- 前言
- 第1章 Activity的生命周期和啟動模式
- 1.1 Activity的生命周期全面分析
- 1.1.1 典型情況下的生命周期分析
- 1.1.2 異常情況下的生命周期分析
- 1.2 Activity的啟動模式
- 1.2.1 Activity的LaunchMode
- 1.2.2 Activity的Flags
- 1.3 IntentFilter的匹配規則
- 第2章 IPC機制
- 2.1 Android IPC簡介
- 2.2 Android中的多進程模式
- 2.2.1 開啟多進程模式
- 2.2.2 多進程模式的運行機制
- 2.3 IPC基礎概念介紹
- 2.3.1 Serializable接口
- 2.3.2 Parcelable接口
- 2.3.3 Binder
- 2.4 Android中的IPC方式
- 2.4.1 使用Bundle
- 2.4.2 使用文件共享
- 2.4.3 使用Messenger
- 2.4.4 使用AIDL
- 2.4.5 使用ContentProvider
- 2.4.6 使用Socket
- 2.5 Binder連接池
- 2.6 選用合適的IPC方式
- 第3章 View的事件體系
- 3.1 View基礎知識
- 3.1.1 什么是View
- 3.1.2 View的位置參數
- 3.1.3 MotionEvent和TouchSlop
- 3.1.4 VelocityTracker、GestureDetector和Scroller
- 3.2 View的滑動
- 3.2.1 使用scrollTo/scrollBy
- 3.2.2 使用動畫
- 3.2.3 改變布局參數
- 3.2.4 各種滑動方式的對比
- 3.3 彈性滑動
- 3.3.1 使用Scroller7
- 3.3.2 通過動畫
- 3.3.3 使用延時策略
- 3.4 View的事件分發機制
- 3.4.1 點擊事件的傳遞規則
- 3.4.2 事件分發的源碼解析
- 3.5 View的滑動沖突
- 3.5.1 常見的滑動沖突場景
- 3.5.2 滑動沖突的處理規則
- 3.5.3 滑動沖突的解決方式
- 第4章 View的工作原理
- 4.1 初識ViewRoot和DecorView
- 4.2 理解MeasureSpec
- 4.2.1 MeasureSpec
- 4.2.2 MeasureSpec和LayoutParams的對應關系
- 4.3 View的工作流程
- 4.3.1 measure過程
- 4.3.2 layout過程
- 4.3.3 draw過程
- 4.4 自定義View
- 4.4.1 自定義View的分類
- 4.4.2 自定義View須知
- 4.4.3 自定義View示例
- 4.4.4 自定義View的思想
- 第5章 理解RemoteViews
- 5.1 RemoteViews的應用
- 5.1.1 RemoteViews在通知欄上的應用
- 5.1.2 RemoteViews在桌面小部件上的應用
- 5.1.3 PendingIntent概述
- 5.2 RemoteViews的內部機制
- 5.3 RemoteViews的意義
- 第6章 Android的Drawable
- 6.1 Drawable簡介
- 6.2 Drawable的分類
- 6.2.1 BitmapDrawable2
- 6.2.2 ShapeDrawable
- 6.2.3 LayerDrawable
- 6.2.4 StateListDrawable
- 6.2.5 LevelListDrawable
- 6.2.6 TransitionDrawable
- 6.2.7 InsetDrawable
- 6.2.8 ScaleDrawable
- 6.2.9 ClipDrawable
- 6.3 自定義Drawable
- 第7章 Android動畫深入分析
- 7.1 View動畫
- 7.1.1 View動畫的種類
- 7.1.2 自定義View動畫
- 7.1.3 幀動畫
- 7.2 View動畫的特殊使用場景
- 7.2.1 LayoutAnimation
- 7.2.2 Activity的切換效果
- 7.3 屬性動畫
- 7.3.1 使用屬性動畫
- 7.3.2 理解插值器和估值器 /
- 7.3.3 屬性動畫的監聽器
- 7.3.4 對任意屬性做動畫
- 7.3.5 屬性動畫的工作原理
- 7.4 使用動畫的注意事項
- 第8章 理解Window和WindowManager
- 8.1 Window和WindowManager
- 8.2 Window的內部機制
- 8.2.1 Window的添加過程
- 8.2.2 Window的刪除過程
- 8.2.3 Window的更新過程
- 8.3 Window的創建過程
- 8.3.1 Activity的Window創建過程
- 8.3.2 Dialog的Window創建過程
- 8.3.3 Toast的Window創建過程
- 第9章 四大組件的工作過程
- 9.1 四大組件的運行狀態
- 9.2 Activity的工作過程
- 9.3 Service的工作過程
- 9.3.1 Service的啟動過程
- 9.3.2 Service的綁定過程
- 9.4 BroadcastReceiver的工作過程
- 9.4.1 廣播的注冊過程
- 9.4.2 廣播的發送和接收過程
- 9.5 ContentProvider的工作過程
- 第10章 Android的消息機制
- 10.1 Android的消息機制概述
- 10.2 Android的消息機制分析
- 10.2.1 ThreadLocal的工作原理
- 10.2.2 消息隊列的工作原理
- 10.2.3 Looper的工作原理
- 10.2.4 Handler的工作原理
- 10.3 主線程的消息循環
- 第11章 Android的線程和線程池
- 11.1 主線程和子線程
- 11.2 Android中的線程形態
- 11.2.1 AsyncTask
- 11.2.2 AsyncTask的工作原理
- 11.2.3 HandlerThread
- 11.2.4 IntentService
- 11.3 Android中的線程池
- 11.3.1 ThreadPoolExecutor
- 11.3.2 線程池的分類
- 第12章 Bitmap的加載和Cache
- 12.1 Bitmap的高效加載
- 12.2 Android中的緩存策略
- 12.2.1 LruCache
- 12.2.2 DiskLruCache
- 12.2.3 ImageLoader的實現446
- 12.3 ImageLoader的使用
- 12.3.1 照片墻效果
- 12.3.2 優化列表的卡頓現象
- 第13章 綜合技術
- 13.1 使用CrashHandler來獲取應用的crash信息
- 13.2 使用multidex來解決方法數越界
- 13.3 Android的動態加載技術
- 13.4 反編譯初步
- 13.4.1 使用dex2jar和jd-gui反編譯apk
- 13.4.2 使用apktool對apk進行二次打包
- 第14章 JNI和NDK編程
- 14.1 JNI的開發流程
- 14.2 NDK的開發流程
- 14.3 JNI的數據類型和類型簽名
- 14.4 JNI調用Java方法的流程
- 第15章 Android性能優化
- 15.1 Android的性能優化方法
- 15.1.1 布局優化
- 15.1.2 繪制優化
- 15.1.3 內存泄露優化
- 15.1.4 響應速度優化和ANR日志分析
- 15.1.5 ListView和Bitmap優化
- 15.1.6 線程優化
- 15.1.7 一些性能優化建議
- 15.2 內存泄露分析之MAT工具
- 15.3 提高程序的可維護性