Activity啟動分析(二)--建立Window和View
一.Activity啟動
Activity由ActivityThread負責啟動。 ActivityThread的分析將在《ActivityThread分析》中,在此,只需要知道建立activity的入口在ActivityThread就行,不影響以下的分析。
ActivityThread.java
private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
r.intent.setExtrasClassLoader(cl);
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
return activity;
}
二。呼叫Activity的attach方法。
ActivityThread.java
private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ContextImpl appContext = new ContextImpl();
appContext.init(r.packageInfo, r.token, this);
appContext.setOuterContext(activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mConfiguration);
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.lastNonConfigurationInstance,
r.lastNonConfigurationChildInstances, config);
}
三。Activity的attach實現
1.attach的實現
Activity.java //Activity implement Window.Callback
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,
Object lastNonConfigurationInstance,
HashMap<String,Object> lastNonConfigurationChildInstances,
Configuration config) {
attachBaseContext(context); //ContextThemeWrapper中實現,賦值給mBase
mWindow = PolicyManager.makeNewWindow(this); //建立window,實際上是一個PhoneWindow物件
mWindow.setCallback(this); //設定Window.Callback,因為Activity implement Window.Callback
mWindow.setWindowManager(null, mToken, mComponent.flattenToString());
mWindowManager = mWindow.getWindowManager();
}
2.PolicyManager.makeNewWindow實現
(1).PolicyManager.java
private static final String POLICY_IMPL_CLASS_NAME =
"com.android.internal.policy.impl.Policy";
private static final IPolicy sPolicy;
static {
// Pull in the actual implementation of the policy at run-time
Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
sPolicy = (IPolicy)policyClass.newInstance();
}
public static Window makeNewWindow(Context context) {
return sPolicy.makeNewWindow(context);
}
(2).Policy.java //Policy implements IPolicy
public PhoneWindow makeNewWindow(Context context) {
return new PhoneWindow(context);
}
3.設定WindowManager
mWindow.setWindowManager(null, mToken, mComponent.flattenToString()); //為Window中的WindowManager賦值
mWindowManager = mWindow.getWindowManager(); //為Acitivity中的WindowManager賦值
WindowManager只是一個interface,實現類有兩個:Window.LocalWindowManager和WindowManagerImpl。
(1).Window.LocalWindowManager實現,只是對WindowManagerImpl的封裝呼叫。
private class LocalWindowManager implements WindowManager {
private final WindowManager mWindowManager;
LocalWindowManager(WindowManager wm) {
mWindowManager = wm;
}
public final void addView(View view, ViewGroup.LayoutParams params) {
//some code to check params here
mWindowManager.addView(view, params);
}
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
mWindowManager.updateViewLayout(view, params);
}
public final void removeView(View view) {
mWindowManager.removeView(view);
}
public final void removeViewImmediate(View view) {
mWindowManager.removeViewImmediate(view);
}
}
(2).Window.setWindowManager實現分析
public void setWindowManager(WindowManager wm, IBinder appToken, String appName) {
if (wm == null) {
wm = WindowManagerImpl.getDefault();
}
mWindowManager = new LocalWindowManager(wm);
}
四。回撥Activity的onCreate方法。
(1). ActivityThread.java
private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
(2). Instrumentation.java
public void callActivityOnCreate(Activity activity, Bundle icicle) {
activity.onCreate(icicle);
}
五。Activity中setContentView(int layout)分析
Activity.java
public void setContentView(int layoutResID) {
getWindow().setContentView(layoutResID);
}
public Window getWindow() {
return mWindow; //mWindow = PolicyManager.makeNewWindow(this);
}
六。Window中setContentView(int layout)分析
(1)PhoneWindow.java //因為Window是個abstract class, mWindow實際上是一個PhoneWindow物件
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
} else {
mContentParent.removeAllViews();
}
mLayoutInflater.inflate(layoutResID, mContentParent);
final Callback cb = getCallback();
if (cb != null) {
cb.onContentChanged();
}
}
(2) installDecor()分析 //PhoneWindow.java中
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor();
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
}
}
mDecor: class DecorView extends FrameLayout
mContentParent: class ViewGroup
(3)generateDecor()分析
protected DecorView generateDecor() {
return new DecorView(getContext(), -1);
}
DecorView:繼承自FrameLayout,可以理解成視窗修飾,這個視窗修飾可以有各種style,比如標題欄,顯示進度條等。常見的視窗修飾的layout路徑為:frameworks/base/core/res/res/layout,比如R.layout.dialog_title_icons, R.layout.screen_title_icons.
(4)generateLayout()分析
protected ViewGroup generateLayout(DecorView decor) {
// Inflate the window decor.
int layoutResource;
if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
if (mIsFloating) {
layoutResource = com.android.internal.R.layout.dialog_title_icons;
} else {
layoutResource = com.android.internal.R.layout.screen_title_icons;
}
} else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0) {
layoutResource = com.android.internal.R.layout.screen_progress;
} else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
if (mIsFloating) {
layoutResource = com.android.internal.R.layout.dialog_custom_title;
} else {
layoutResource = com.android.internal.R.layout.screen_custom_title;
}
} else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
if (mIsFloating) {
layoutResource = com.android.internal.R.layout.dialog_title;
} else {
layoutResource = com.android.internal.R.layout.screen_title;
}
} else {
layoutResource = com.android.internal.R.layout.screen_simple;
}
View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
if (contentParent == null) {
throw new RuntimeException("Window couldn't find content container view");
}
return contentParent;
}
DecorView的樣式的定義:第一種是在Activity中onCreate中呼叫requestFeature()。另一種是在AndroidManifest.xml中配置android:theme="xxx".
DecorView新增View:generateLayout的前部分程式碼,就是確定DecorView的樣式,然後inflate這個layout檔案,再呼叫DecorView.addView()新增到DecorView上。
mContentParent賦值:視窗修飾的layout中必須有一個FrameLayout,id為ID_ANDROID_CONTENT(實際上id=content),將這個FrameLayout賦值給mContentParent。
(5)新增視窗內容到mContentParent。
mLayoutInflater.inflate(layoutResID, mContentParent);
將activity傳入的layoutRes新增到視窗裝飾中。
(6)Window.Callback回撥
final Callback cb = getCallback(); //Activity實現了Window.Callback介面,並且在建立PhoneWindow後,呼叫mWindow.setCallback(this)
if (cb != null) {
cb.onContentChanged();
}
七。通知WmS,顯示DecorView
Activity準備好後會通知AmS,AmS通過一些條件判斷,回撥Activity的makeVisible().
(1.) Activity.java
public void setVisible(boolean visible) {
if (mVisibleFromClient != visible) {
mVisibleFromClient = visible;
if (mVisibleFromServer) {
if (visible) makeVisible();
else mDecor.setVisibility(View.INVISIBLE);
}
}
}
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes()); //通過WindowManager將DecorView新增到window。
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
public Window getWindow() {
return mWindow;
}
(2.) Window.java
public final WindowManager.LayoutParams getAttributes() {
return mWindowAttributes;
}
private final WindowManager.LayoutParams mWindowAttributes =
new WindowManager.LayoutParams();
(3.) WindowManager.LayoutParams
public LayoutParams() {
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
type = TYPE_APPLICATION;
format = PixelFormat.OPAQUE;
}
(4.)Window.LocalWindowManager
wm.addView(mDecor, getWindow().getAttributes())分析
這個wm是LocalWindowManager,是對WindowManagerImpl的封裝,目地是對params進行一些校驗後,再呼叫WindowManagerImpl的addView。
校驗params:
if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
} else {
}
八。WindowManagerImpl.addView分析
方法:addView(View view, ViewGroup.LayoutParams params, boolean nest);
class WindowManagerImpl extends WindowManager, interface WindowManager extends ViewManager
3個成員變數:
private View[] mViews;//每個view物件都將成為WmS所認為的一個視窗
private ViewRoot[] mRoots;//每個view對應一個ViewRoot
private WindowManager.LayoutParams[] mParams;//對應mViews的每個view的param
(1.)檢查view是否已經新增過,不允許重複新增
int index = findViewLocked(view, false);
if (index >= 0) {
if (!nest) {
throw new IllegalStateException("View " + view
+ " has already been added to the window manager.");
}
root = mRoots[index];
root.mAddNesting++;
// Update layout parameters.
view.setLayoutParams(wparams);
root.setLayoutParams(wparams, true);
return;
}
(2.)檢查視窗型別是否為sub window。如果是,則找到它的父視窗,並儲存在臨時變數panelParentView中,為下面呼叫ViewRoot的setView使用。
if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
final int count = mViews != null ? mViews.length : 0;
for (int i=0; i<count; i++) {
if (mRoots[i].mWindow.asBinder() == wparams.token) {
panelParentView = mViews[i];
}
}
}
(3.)建立一個新的ViewRoot,上文說過每個view都對應一個ViewRoot。
root = new ViewRoot(view.getContext());
root.mAddNesting = 1;
ViewRoot的構造方法:
public ViewRoot(Context context) {
super();
// Initialize the statics when this class is first instantiated. This is
// done here instead of in the static block because Zygote does not
// allow the spawning of threads.
getWindowSession(context.getMainLooper()); //init static IWindowSession sWindowSession;
mThread = Thread.currentThread();
mLocation = new WindowLeaked(null);
mLocation.fillInStackTrace();
mWidth = -1;
mHeight = -1;
mDirty = new Rect();
mTempRect = new Rect();
mVisRect = new Rect();
mWinFrame = new Rect();
mWindow = new W(this, context); // class W extends IWindow.Stub
mInputMethodCallback = new InputMethodCallback(this);
mViewVisibility = View.GONE;
mTransparentRegion = new Region();
mPreviousTransparentRegion = new Region();
mFirst = true; // true for the first time the view is added
mAdded = false;
mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this);
mViewConfiguration = ViewConfiguration.get(context);
mDensity = context.getResources().getDisplayMetrics().densityDpi;
}
(4.)將view,root和param新增到上面的3個陣列中。
if (mViews == null) {
index = 1;
mViews = new View[1];
mRoots = new ViewRoot[1];
mParams = new WindowManager.LayoutParams[1];
} else {
index = mViews.length + 1;
Object[] old = mViews; //儲存原來的陣列
mViews = new View[index]; //新建一個陣列,長度+1
System.arraycopy(old, 0, mViews, 0, index-1); //將原來的陣列copy到新建的陣列中
old = mRoots;
mRoots = new ViewRoot[index];
System.arraycopy(old, 0, mRoots, 0, index-1);
old = mParams;
mParams = new WindowManager.LayoutParams[index];
System.arraycopy(old, 0, mParams, 0, index-1);
}
index--;
mViews[index] = view;
mRoots[index] = root;
mParams[index] = wparams;
(5.)呼叫ViewRoot的setView方法,完成最後的新增工作。
九。ViewRoot的setView分析
引數意義:
view: WindowManagerImpl中mViews陣列中的元素,也就是新建的視窗介面
attrs:視窗引數,描述視窗的風格,大小,位置。attrs中的token變數指明瞭該視窗和activity的關係。
panelParentView:view的父視窗
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;//給成員變數賦值。
mWindowAttributes.copyFrom(attrs);//給成員變數賦值。
attrs = mWindowAttributes;//給成員變數賦值。
………………………………
mSoftInputMode = attrs.softInputMode;//給成員變數賦值。
mWindowAttributesChanged = true;//給成員變數賦值。
mAttachInfo.mRootView = view;//給成員變數賦值。
if (panelParentView != null) {
mAttachInfo.mPanelParentWindowToken
= panelParentView.getApplicationWindowToken();
}
………………………………
requestLayout(); //發出重繪請求,使該 在相應訊息前變的可見
………………………………
try {
//通知WmS,新增視窗
res = sWindowSession.add(mWindow, mWindowAttributes,
getHostVisibility(), mAttachInfo.mContentInsets,
mInputChannel);
} catch (RemoteException e) {
}
}
}
}
十。sWindowSession.add分析
(1)IWindowSession是一個aidl介面,實現類是在WmS中:class Session extends IWindowSession.Stub
(2)sWindowSession的初始化: //static IWindowSession sWindowSession;
public static IWindowSession getWindowSession(Looper mainLooper) {
synchronized (mStaticInit) {
if (!mInitialized) {
try {
InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
sWindowSession = IWindowManager.Stub.asInterface(
ServiceManager.getService("window")) //先獲得WmS
.openSession(imm.getClient(), imm.getInputContext()); //再通過WmS獲取分配的IWindowSession
mInitialized = true;
} catch (RemoteException e) {
}
}
return sWindowSession;
}
}
(3)sWindowSession為static,WmS為每個程式只分配1個。呼叫sWindowSession.add是app請求WmS新增視窗的唯一入口。
總結:至此,從客戶端的角度講,已經完成了視窗建立的全部工作。
Activity由ActivityThread負責啟動。 ActivityThread的分析將在《ActivityThread分析》中,在此,只需要知道建立activity的入口在ActivityThread就行,不影響以下的分析。
ActivityThread.java
private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
r.intent.setExtrasClassLoader(cl);
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
return activity;
}
二。呼叫Activity的attach方法。
ActivityThread.java
private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ContextImpl appContext = new ContextImpl();
appContext.init(r.packageInfo, r.token, this);
appContext.setOuterContext(activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mConfiguration);
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.lastNonConfigurationInstance,
r.lastNonConfigurationChildInstances, config);
}
三。Activity的attach實現
1.attach的實現
Activity.java //Activity implement Window.Callback
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,
Object lastNonConfigurationInstance,
HashMap<String,Object> lastNonConfigurationChildInstances,
Configuration config) {
attachBaseContext(context); //ContextThemeWrapper中實現,賦值給mBase
mWindow = PolicyManager.makeNewWindow(this); //建立window,實際上是一個PhoneWindow物件
mWindow.setCallback(this); //設定Window.Callback,因為Activity implement Window.Callback
mWindow.setWindowManager(null, mToken, mComponent.flattenToString());
mWindowManager = mWindow.getWindowManager();
}
2.PolicyManager.makeNewWindow實現
(1).PolicyManager.java
private static final String POLICY_IMPL_CLASS_NAME =
"com.android.internal.policy.impl.Policy";
private static final IPolicy sPolicy;
static {
// Pull in the actual implementation of the policy at run-time
Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
sPolicy = (IPolicy)policyClass.newInstance();
}
public static Window makeNewWindow(Context context) {
return sPolicy.makeNewWindow(context);
}
(2).Policy.java //Policy implements IPolicy
public PhoneWindow makeNewWindow(Context context) {
return new PhoneWindow(context);
}
3.設定WindowManager
mWindow.setWindowManager(null, mToken, mComponent.flattenToString()); //為Window中的WindowManager賦值
mWindowManager = mWindow.getWindowManager(); //為Acitivity中的WindowManager賦值
WindowManager只是一個interface,實現類有兩個:Window.LocalWindowManager和WindowManagerImpl。
(1).Window.LocalWindowManager實現,只是對WindowManagerImpl的封裝呼叫。
private class LocalWindowManager implements WindowManager {
private final WindowManager mWindowManager;
LocalWindowManager(WindowManager wm) {
mWindowManager = wm;
}
public final void addView(View view, ViewGroup.LayoutParams params) {
//some code to check params here
mWindowManager.addView(view, params);
}
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
mWindowManager.updateViewLayout(view, params);
}
public final void removeView(View view) {
mWindowManager.removeView(view);
}
public final void removeViewImmediate(View view) {
mWindowManager.removeViewImmediate(view);
}
}
(2).Window.setWindowManager實現分析
public void setWindowManager(WindowManager wm, IBinder appToken, String appName) {
if (wm == null) {
wm = WindowManagerImpl.getDefault();
}
mWindowManager = new LocalWindowManager(wm);
}
四。回撥Activity的onCreate方法。
(1). ActivityThread.java
private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
(2). Instrumentation.java
public void callActivityOnCreate(Activity activity, Bundle icicle) {
activity.onCreate(icicle);
}
五。Activity中setContentView(int layout)分析
Activity.java
public void setContentView(int layoutResID) {
getWindow().setContentView(layoutResID);
}
public Window getWindow() {
return mWindow; //mWindow = PolicyManager.makeNewWindow(this);
}
六。Window中setContentView(int layout)分析
(1)PhoneWindow.java //因為Window是個abstract class, mWindow實際上是一個PhoneWindow物件
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
} else {
mContentParent.removeAllViews();
}
mLayoutInflater.inflate(layoutResID, mContentParent);
final Callback cb = getCallback();
if (cb != null) {
cb.onContentChanged();
}
}
(2) installDecor()分析 //PhoneWindow.java中
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor();
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
}
}
mDecor: class DecorView extends FrameLayout
mContentParent: class ViewGroup
(3)generateDecor()分析
protected DecorView generateDecor() {
return new DecorView(getContext(), -1);
}
DecorView:繼承自FrameLayout,可以理解成視窗修飾,這個視窗修飾可以有各種style,比如標題欄,顯示進度條等。常見的視窗修飾的layout路徑為:frameworks/base/core/res/res/layout,比如R.layout.dialog_title_icons, R.layout.screen_title_icons.
(4)generateLayout()分析
protected ViewGroup generateLayout(DecorView decor) {
// Inflate the window decor.
int layoutResource;
if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
if (mIsFloating) {
layoutResource = com.android.internal.R.layout.dialog_title_icons;
} else {
layoutResource = com.android.internal.R.layout.screen_title_icons;
}
} else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0) {
layoutResource = com.android.internal.R.layout.screen_progress;
} else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
if (mIsFloating) {
layoutResource = com.android.internal.R.layout.dialog_custom_title;
} else {
layoutResource = com.android.internal.R.layout.screen_custom_title;
}
} else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
if (mIsFloating) {
layoutResource = com.android.internal.R.layout.dialog_title;
} else {
layoutResource = com.android.internal.R.layout.screen_title;
}
} else {
layoutResource = com.android.internal.R.layout.screen_simple;
}
View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
if (contentParent == null) {
throw new RuntimeException("Window couldn't find content container view");
}
return contentParent;
}
DecorView的樣式的定義:第一種是在Activity中onCreate中呼叫requestFeature()。另一種是在AndroidManifest.xml中配置android:theme="xxx".
DecorView新增View:generateLayout的前部分程式碼,就是確定DecorView的樣式,然後inflate這個layout檔案,再呼叫DecorView.addView()新增到DecorView上。
mContentParent賦值:視窗修飾的layout中必須有一個FrameLayout,id為ID_ANDROID_CONTENT(實際上id=content),將這個FrameLayout賦值給mContentParent。
(5)新增視窗內容到mContentParent。
mLayoutInflater.inflate(layoutResID, mContentParent);
將activity傳入的layoutRes新增到視窗裝飾中。
(6)Window.Callback回撥
final Callback cb = getCallback(); //Activity實現了Window.Callback介面,並且在建立PhoneWindow後,呼叫mWindow.setCallback(this)
if (cb != null) {
cb.onContentChanged();
}
七。通知WmS,顯示DecorView
Activity準備好後會通知AmS,AmS通過一些條件判斷,回撥Activity的makeVisible().
(1.) Activity.java
public void setVisible(boolean visible) {
if (mVisibleFromClient != visible) {
mVisibleFromClient = visible;
if (mVisibleFromServer) {
if (visible) makeVisible();
else mDecor.setVisibility(View.INVISIBLE);
}
}
}
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes()); //通過WindowManager將DecorView新增到window。
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
public Window getWindow() {
return mWindow;
}
(2.) Window.java
public final WindowManager.LayoutParams getAttributes() {
return mWindowAttributes;
}
private final WindowManager.LayoutParams mWindowAttributes =
new WindowManager.LayoutParams();
(3.) WindowManager.LayoutParams
public LayoutParams() {
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
type = TYPE_APPLICATION;
format = PixelFormat.OPAQUE;
}
(4.)Window.LocalWindowManager
wm.addView(mDecor, getWindow().getAttributes())分析
這個wm是LocalWindowManager,是對WindowManagerImpl的封裝,目地是對params進行一些校驗後,再呼叫WindowManagerImpl的addView。
校驗params:
if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
} else {
}
八。WindowManagerImpl.addView分析
方法:addView(View view, ViewGroup.LayoutParams params, boolean nest);
class WindowManagerImpl extends WindowManager, interface WindowManager extends ViewManager
3個成員變數:
private View[] mViews;//每個view物件都將成為WmS所認為的一個視窗
private ViewRoot[] mRoots;//每個view對應一個ViewRoot
private WindowManager.LayoutParams[] mParams;//對應mViews的每個view的param
(1.)檢查view是否已經新增過,不允許重複新增
int index = findViewLocked(view, false);
if (index >= 0) {
if (!nest) {
throw new IllegalStateException("View " + view
+ " has already been added to the window manager.");
}
root = mRoots[index];
root.mAddNesting++;
// Update layout parameters.
view.setLayoutParams(wparams);
root.setLayoutParams(wparams, true);
return;
}
(2.)檢查視窗型別是否為sub window。如果是,則找到它的父視窗,並儲存在臨時變數panelParentView中,為下面呼叫ViewRoot的setView使用。
if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
final int count = mViews != null ? mViews.length : 0;
for (int i=0; i<count; i++) {
if (mRoots[i].mWindow.asBinder() == wparams.token) {
panelParentView = mViews[i];
}
}
}
(3.)建立一個新的ViewRoot,上文說過每個view都對應一個ViewRoot。
root = new ViewRoot(view.getContext());
root.mAddNesting = 1;
ViewRoot的構造方法:
public ViewRoot(Context context) {
super();
// Initialize the statics when this class is first instantiated. This is
// done here instead of in the static block because Zygote does not
// allow the spawning of threads.
getWindowSession(context.getMainLooper()); //init static IWindowSession sWindowSession;
mThread = Thread.currentThread();
mLocation = new WindowLeaked(null);
mLocation.fillInStackTrace();
mWidth = -1;
mHeight = -1;
mDirty = new Rect();
mTempRect = new Rect();
mVisRect = new Rect();
mWinFrame = new Rect();
mWindow = new W(this, context); // class W extends IWindow.Stub
mInputMethodCallback = new InputMethodCallback(this);
mViewVisibility = View.GONE;
mTransparentRegion = new Region();
mPreviousTransparentRegion = new Region();
mFirst = true; // true for the first time the view is added
mAdded = false;
mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this);
mViewConfiguration = ViewConfiguration.get(context);
mDensity = context.getResources().getDisplayMetrics().densityDpi;
}
(4.)將view,root和param新增到上面的3個陣列中。
if (mViews == null) {
index = 1;
mViews = new View[1];
mRoots = new ViewRoot[1];
mParams = new WindowManager.LayoutParams[1];
} else {
index = mViews.length + 1;
Object[] old = mViews; //儲存原來的陣列
mViews = new View[index]; //新建一個陣列,長度+1
System.arraycopy(old, 0, mViews, 0, index-1); //將原來的陣列copy到新建的陣列中
old = mRoots;
mRoots = new ViewRoot[index];
System.arraycopy(old, 0, mRoots, 0, index-1);
old = mParams;
mParams = new WindowManager.LayoutParams[index];
System.arraycopy(old, 0, mParams, 0, index-1);
}
index--;
mViews[index] = view;
mRoots[index] = root;
mParams[index] = wparams;
(5.)呼叫ViewRoot的setView方法,完成最後的新增工作。
九。ViewRoot的setView分析
引數意義:
view: WindowManagerImpl中mViews陣列中的元素,也就是新建的視窗介面
attrs:視窗引數,描述視窗的風格,大小,位置。attrs中的token變數指明瞭該視窗和activity的關係。
panelParentView:view的父視窗
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;//給成員變數賦值。
mWindowAttributes.copyFrom(attrs);//給成員變數賦值。
attrs = mWindowAttributes;//給成員變數賦值。
………………………………
mSoftInputMode = attrs.softInputMode;//給成員變數賦值。
mWindowAttributesChanged = true;//給成員變數賦值。
mAttachInfo.mRootView = view;//給成員變數賦值。
if (panelParentView != null) {
mAttachInfo.mPanelParentWindowToken
= panelParentView.getApplicationWindowToken();
}
………………………………
requestLayout(); //發出重繪請求,使該 在相應訊息前變的可見
………………………………
try {
//通知WmS,新增視窗
res = sWindowSession.add(mWindow, mWindowAttributes,
getHostVisibility(), mAttachInfo.mContentInsets,
mInputChannel);
} catch (RemoteException e) {
}
}
}
}
十。sWindowSession.add分析
(1)IWindowSession是一個aidl介面,實現類是在WmS中:class Session extends IWindowSession.Stub
(2)sWindowSession的初始化: //static IWindowSession sWindowSession;
public static IWindowSession getWindowSession(Looper mainLooper) {
synchronized (mStaticInit) {
if (!mInitialized) {
try {
InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
sWindowSession = IWindowManager.Stub.asInterface(
ServiceManager.getService("window")) //先獲得WmS
.openSession(imm.getClient(), imm.getInputContext()); //再通過WmS獲取分配的IWindowSession
mInitialized = true;
} catch (RemoteException e) {
}
}
return sWindowSession;
}
}
(3)sWindowSession為static,WmS為每個程式只分配1個。呼叫sWindowSession.add是app請求WmS新增視窗的唯一入口。
總結:至此,從客戶端的角度講,已經完成了視窗建立的全部工作。
相關文章
- Activity、View、Window之間關係的分析View
- Android 中MVC例項之Activity,Window和ViewAndroidMVCView
- Android 中Activity,Window和View之間的關係AndroidView
- Activity啟動流程分析
- activity 啟動流程分析
- Activity啟動過程分析
- 深入理解Activity啟動流程和AMS框架(二)框架
- Activity啟動流程原始碼分析原始碼
- 底層剖析 Window 、Activity、 View 三者關係View
- Activity啟動分析(一)--ActivityThreadthread
- Activity、View、Window的理解一篇文章就夠了View
- Android Activity啟動流程原始碼分析Android原始碼
- Android原始碼分析:Activity啟動流程Android原始碼
- Concurrency(二:建立和啟動執行緒)執行緒
- View和Activity的生命週期View
- Activity的啟動過程第二篇
- Android 8.0 原始碼分析 (四) Activity 啟動Android原始碼
- Activity啟動流程分析記錄(Api26)API
- Activity啟動模式模式
- Activity的生命週期和啟動模式模式
- activity的啟動模式模式
- Activity轉換為View和把圖片轉換為ViewView
- whose view is not in the window hierarchy!View
- Android系統原始碼分析--Activity啟動過程Android原始碼
- activity四種啟動模式模式
- Activity的生命週期和啟動模式詳解模式
- Android service裡面啟動activity和alertdialogAndroid
- 深入理解Activity啟動流程和AMS框架(一)框架
- 深入理解Activity啟動流程和AMS框架(三)框架
- Activity 從啟動到佈局繪製的簡單分析
- Activity從啟動到佈局繪製的簡單分析
- Activity啟動模式(GIF 動態演示)模式
- Android自定義View之Window、ViewRootImpl和View的三大流程AndroidView
- grpc python 原始碼分析(1):server 的建立和啟動RPCPython原始碼Server
- View.findViewById()和Activity.findViewById()區別View
- 2-AI–Activity啟動方式AI
- Activity的啟動模式詳解模式
- Activity啟動相關屬性