Window初探
在启动一个Activity时,会走到ActivityThread的handleLaunchActivity方法
/**
* ActivityThread
*/
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent){
...
//初始化WindowManagerGlobal,该类是4.x以后出现的
WindowManagerGlobal.initialize();
//生成Activity
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
...
//执行Activity的Resume
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed);
}
}
Step1 WindowManagerGlobal初始化
WindowManagerGlobal在2.3的版本中是没有的,一个应用会有三个数组来管理当前的窗口
分别是List ,List ,List,旧版本中,这三个数组是在WindowManagerImpl中的,而新版本统一由WindowManagerGlobal管理。
/**
* WindowManagerGlobal
*/
public static void initialize() {
getWindowManagerService();
}
public static IWindowManager getWindowManagerService() {
synchronized (WindowManagerGlobal.class) {
if (sWindowManagerService == null) {
//获取WindowManagerService
sWindowManagerService = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
try {
sWindowManagerService = getWindowManagerService();
ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());
} catch (RemoteException e) {
Log.e(TAG, "Failed to get WindowManagerService, cannot set animator scale", e);
}
}
return sWindowManagerService;
}
}
Step2 performLaunchActivity
performLaunchActivity做了以下重要事情
生成Activity
生成或获得Application
生成ContextImpl
调用activity的attach
间接调用activity的onCreate
public final class ActivityThread {
......
Instrumentation mInstrumentation;
......
private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
......
ComponentName component = r.intent.getComponent();
......
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
......
} catch (Exception e) {
......
}
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
......
if (activity != null) {
Context appContext = createBaseContextForActivity(r, activity);//旧版本是ContextImpl appContext = new ContextImpl();
......
//旧版本有 appContext.setOuterContext(activity); 新版本在createBaseContextForActivity中
......
Configuration config = new Configuration(mConfiguration);
......
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstance,
r.lastNonConfigurationChildInstances, config);
......
mInstrumentation.callActivityOnCreate(activity, r.state);
......
}
......
} catch (SuperNotCalledException e) {
......
} catch (Exception e) {
......
}
return activity;
}
}
Step 3 Activity的Attach
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks {
......
private Window mWindow;
......
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) {
......
mWindow = new PhoneWindow(this);//新版本直接就new了一个phoneWindow,少见,旧版本为PolicyManager.makeNewWindow(this)
mWindow.setCallback(this);//用于获取Window上得到的Event
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
......
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
//setWindowManager的第一个参数为WindowManager,旧版本传了空,新版本通过getSystemService获得(获得的是一个WindowManagerImpl),本质是一样的
mWindow.setWindowManager(null, mToken, mComponent.flattenToString());
mWindowManager = mWindow.getWindowManager();
......
}
......
}
其中PhoneWindow的构造函数非常简单
PhoneWindow继承自Window
public class PhoneWindow extends Window implements MenuBuilder.Callback {
......
// This is the top-level view of the window, containing the window decor.
private DecorView mDecor;
// This is the view in which the window contents are placed. It is either
// mDecor itself, or a child of mDecor where the contents go.
private ViewGroup mContentParent;
......
private LayoutInflater mLayoutInflater;
......
public PhoneWindow(Context context) {
super(context);
mLayoutInflater = LayoutInflater.from(context);
}
......
}
而其父类Window的构造函数也非常简单
public abstract class Window {
......
private final Context mContext;
......
public Window(Context context) {
mContext = context;
}
......
}
Step 4 Window.setManager
public abstract class Window {
......
private WindowManager mWindowManager;
private IBinder mAppToken;
private String mAppName;
......
public void setWindowManager(WindowManager wm,
IBinder appToken, String appName) {
mAppToken = appToken;
mAppName = appName;
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
/*旧版本的代码
public void setWindowManager(WindowManager wm,
IBinder appToken, String appName) {
mAppToken = appToken;
mAppName = appName;
if (wm == null) {
wm = WindowManagerImpl.getDefault();
}
mWindowManager = new LocalWindowManager(wm);
}
*/
......
}
传入的三个参数,第一个是一个WindowManager
第二个是appToken,用于知道该Window是与哪个Activity对应的
第三个是Activity的相关的名字。
我们可以看出一个应用中,旧版本中,只有一个WindowManagerImpl,而其他的都是LocalWindowManager,因为ViewRoot,View,WindowParams的列表都是在WindowManagerImpl中,而新版本中,没有了LocalWindowManager,而有了多个WindowManagerImpl,只要确保WindowManagerImpl的成员变量WindowManagerGlobal唯一就好了。
public final class WindowManagerImpl implements WindowManager {
//新版本添加的,十分重要的一个类
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
private final Display mDisplay;
private final Window mParentWindow;
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mDisplay, parentWindow);
}
}
step 5 setContentView
在Activity attach以后,window和windowmanager就已经准备就绪了接下来就可以走Activity的onCreate,并在里面调用setContentView了
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks {
......
private Window mWindow;
......
public Window getWindow() {
return mWindow;
}
......
public void setContentView(int layoutResID) {
getWindow().setContentView(layoutResID);
}
......
}
这里获得的window是一个phoneWindow的实例,所以调用了phoneWindow的setContentView
public class PhoneWindow extends Window implements MenuBuilder.Callback {
......
// This is the view in which the window contents are placed. It is either
// mDecor itself, or a child of mDecor where the contents go.
private ViewGroup mContentParent;
private DecorView mDecor;
......
@Override
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();
}
}
......
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor();
......
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
......
}
}
}
phoneWindow中有两个重要的成员变量
mDecor:代表该窗口的界面,包含标题和内容
mContentParent :代表该窗口的内容,对应的是android.R.id.content
而我们自己的view则是mContentParent的一个子View
setContentView做了两件事
1.initDecor 生成一个DecorView,调用generateLayout方法,把窗口装饰View设为mDocor的子View。
窗口装饰的View可以大致理解为一个垂直的LinearLayout,上部分是Title,下部分是Content。
窗口装饰的View是通过xml生成的。有很多种,但区别不大:
R.layout.screen_title
R.layout.screen_simple
R.layout.screen_custom_title等等
但是他们有一个共同的特点,就是包含一个id为content的FrameLayout
2.inflate我们的view,并将该view设为mContentParent的子View
至此,setContentView就完成了。
step 6 handleResumeActivity
public final class ActivityThread {
......
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
......
ActivityClientRecord r = performResumeActivity(token, clearHide);
if (r != null) {
final Activity a = r.activity;
......
// If the window hasn't yet been added to the window manager,
// and this guy didn't finish itself or start another activity,
// then go ahead and add the window.
boolean willBeVisible = !a.mStartedActivity;
if (!willBeVisible) {
try {
willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(
a.getActivityToken());
} catch (RemoteException e) {
}
}
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
......
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
wm.addView(decor, l);
}
}
......
}
......
}
......
}
这个方法非常简单好理解,最主要的就是调用了WindowManagerImpl的addView方法
step 7 WimdowManagerGlobal 的 addView
public final class WindowManagerImpl implements WindowManager {
public void addView(@NonNull View view,
@NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mDisplay, mParentWindow);
}
}
调用了WindowManagerGlobal的addView。
WindowManagerGlobal
WindowManagerGlobal中有三个List:mViews 、mRoots、mParams
addView的本质就是生成一个ViewRoot,调用ViewRoot的setView。并将View、ViewRoot、Params加入List。
52 public final class WindowManagerGlobal {
114 private final ArrayList<View> mViews = new ArrayList<View>();
115 private final ArrayList<ViewRootImpl> mRoots =
new ArrayList<ViewRootImpl>();
116 private final ArrayList<WindowManager.LayoutParams> mParams =
117 new ArrayList<WindowManager.LayoutParams>();
204 public void addView(View view, ViewGroup.LayoutParams params,
205 Display display, Window parentWindow) {
206 if (view == null) {
207 throw new IllegalArgumentException("view must not be null");
208 }
209 if (display == null) {
210 throw new IllegalArgumentException("display must not be null");
211 }
212 if (!(params instanceof WindowManager.LayoutParams)) {
213 throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
214 }
//以上为校验
215
216 final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
217 if (parentWindow != null) {
218 parentWindow.adjustLayoutParamsForSubWindow(wparams);
219 } else {
220 // If there's no parent and we're running on L or above (or in the
221 // system context), assume we want hardware acceleration.
222 final Context context = view.getContext();
223 if (context != null
224 && context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
225 wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
226 }
227 }
228
229 ViewRootImpl root;
230 View panelParentView = null;
231
232 synchronized (mLock) {
233 // Start watching for system property changes.
234 if (mSystemPropertyUpdater == null) {
235 mSystemPropertyUpdater = new Runnable() {
236 @Override public void More ...run() {
237 synchronized (mLock) {
238 for (int i = mRoots.size() - 1; i >= 0; --i) {
239 mRoots.get(i).loadSystemProperties();
240 }
241 }
242 }
243 };
244 SystemProperties.addChangeCallback(mSystemPropertyUpdater);
245 }
246
247 int index = findViewLocked(view, false);
248 if (index >= 0) {//如果View已经被加入
249 if (mDyingViews.contains(view)) {
250 // Don't wait for MSG_DIE to make it's way through root's queue.
251 mRoots.get(index).doDie();
252 } else {
253 throw new IllegalStateException("View " + view
254 + " has already been added to the window manager.");
255 }
256 // The previous removeView() had not completed executing. Now it has.
257 }
258
259 // If this is a panel window, then find the window it is being
260 // attached to for future reference.
261 if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
262 wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
263 final int count = mViews.size();
264 for (int i = 0; i < count; i++) {
265 if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
266 panelParentView = mViews.get(i);
267 }
268 }
269 }
270 //重点 生成一个ViewRootImpl
271 root = new ViewRootImpl(view.getContext(), display);
272
273 view.setLayoutParams(wparams);
274 //加入数组
275 mViews.add(view);
276 mRoots.add(root);
277 mParams.add(wparams);
278 }
279
280 // do this last because it fires off messages to start doing things
281 try {
//重点中的重点,调用root的setView
282 root.setView(view, wparams, panelParentView);
283 } catch (RuntimeException e) {
284 // BadTokenException or InvalidDisplayException, clean up.
285 synchronized (mLock) {
286 final int index = findViewLocked(view, false);
287 if (index >= 0) {
288 removeViewLocked(index, true);
289 }
290 }
291 throw e;
292 }
293 }
step 8 ViewRootImpl setView
ViewRootImpl 在 低版本叫 ViewRoot
99 public final class More ...ViewRootImpl implements ViewParent,
100 View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
140 final Context mContext;
141 final IWindowSession mWindowSession;
154 final WindowManager.LayoutParams mWindowAttributes =
new WindowManager.LayoutParams();
155
156 final W mWindow; //IBinder
162 View mView;
3393 final ViewRootHandler mHandler = new ViewRootHandler();
444 public void setView(View view,
WindowManager.LayoutParams attrs,
View panelParentView){
445 synchronized (this) {
446 if (mView == null) {
447 mView = view;
......
454 mWindowAttributes.copyFrom(attrs);
455 ......
508 if (panelParentView != null) {
509 mAttachInfo.mPanelParentWindowToken
510 = panelParentView.getApplicationWindowToken();
511 }
512 mAdded = true;
513 int res; /* = WindowManagerImpl.ADD_OKAY; */
514
515 // Schedule the first layout -before- adding to the window
516 // manager, to make sure we do the relayout before receiving
517 // any other events from the system.
518 requestLayout();
519 if ((mWindowAttributes.inputFeatures
520 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
521 mInputChannel = new InputChannel();
522 }
523 try {
......
527 res = mWindowSession.addToDisplay(mWindow,
mSeq, mWindowAttributes,
528 getHostVisibility(), mDisplay.getDisplayId(),
529 mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mInputChannel);
530 } catch (RemoteException e) {
531 mAdded = false;
......
538 throw new RuntimeException("Adding window failed", e);
539 } finally {
540 if (restore) {
541 attrs.restore();
542 }
543 }
544
......
615 view.assignParent(this);
......
645 }
}
ViewRoot类的成员函数setView执行两个操作:
1. 调用ViewRoot类的另外一个成员函数requestLayout来请求对应用程序窗口视图的UI作第一次布局。
2. 调用ViewRoot类的静态成员变量sWindowSession所描述的一个类型为Session的Binder代理对象的成员函数add来请求WindowManagerService增加一个WindowState对象,以便可以用来描述当前正在处理的一个ViewRoot所关联的一个应用程序窗口。
到这里,客户端部分就结束了