Android窗口机制(一)初识Android的窗口结构
Android窗口机制(二)Window,PhoneWindow,DecorView,setContentView源码理解
Android窗口机制(三)Window和WindowManager的建立与Activity
Android窗口机制(四)ViewRootImpl与View和WindowManager
Android窗口机制(五)最终章:WindowManager.LayoutParams和Token以及其余窗口Dialog,Toastjava
前两篇文章跟你们介绍了Window,PhoneWindow,DecorView他们间的联系,以及他们之间的理解。讲到Window你们确定会想到常见的WindowManager,二者确定是发生过关系的。此外对于Window和WindowManager的建立问题,正是下面要介绍的。android
了解他们前,咱们先来看个结构app
Paste_Image.pngide
/** Interface to let you add and remove child views to an Activity. To get an instance * of this class, call {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}. */ public interface ViewManager { public void addView(View view, ViewGroup.LayoutParams params); public void updateViewLayout(View view, ViewGroup.LayoutParams params); public void removeView(View view); }
ViewManager接口定义了一组规则,也就是add、update、remove的操做View接口。也就是说ViewManager是用来添加和移除activity中View的接口,能够经过Context.getSystemService()获取实例。
咱们看下ViewManager的实现类布局
public abstract class ViewGroup extends View implements ViewParent, ViewManager { private static final String TAG = "ViewGroup"; ... public void addView(View child, LayoutParams params) { addView(child, -1, params); } /* * @param child the child view to add * @param index the position at which to add the child or -1 to add last * @param params the layout parameters to set on the child */ public void addView(View child, int index, LayoutParams params) { // addViewInner() will call child.requestLayout() when setting the new LayoutParams // therefore, we call requestLayout() on ourselves before, so that the child's request // will be blocked at our level requestLayout(); invalidate(true); addViewInner(child, index, params, false); } ...
能够看到ViewGroup里面实现了ViewManager接口,View经过ViewGroup的addView方法添加到ViewGroup中,而ViewGroup层层嵌套到最顶级都会显示在在一个窗口Window中post
咱们仍是看下源码说明学习
/* The interface that apps use to talk to the window manager. Use Context.getSystemService(Context.WINDOW_SERVICE) to get one of these. */ public interface WindowManager extends ViewManager { public static class BadTokenException extends RuntimeException{...} public static class InvalidDisplayException extends RuntimeException{...} public Display getDefaultDisplay(); public void removeViewImmediate(View view); public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable
能够看到WindowManager是一个接口,并且它继承与ViewManager。WindowManager字面理解就是窗口管理器,每个窗口管理器都与一个的窗口显示绑定。获取实例能够经过
Context.getSystemService(Context.WINDOW_SERVICE)获取。既然继承了ViewManager,那么它也就能够进行添加删除View的操做了,不过它的操做放在它的实现类WindowManagerImpl里面。成员变量里面this
WindowManager的实现类spa
public final class WindowManagerImpl implements WindowManager { private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); private final Display mDisplay; private final Window mParentWindow; @Override public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyDefaultToken(params); mGlobal.addView(view, params, mDisplay, mParentWindow); } ... @Override public void removeView(View view) { mGlobal.removeView(view, false); } }
能够看到WindowManagerImpl里面有一个成员变量WindowManagerGlobal,而真正的实现则是在WindowManagerGlobal了,相似代理,只不过WindowManagerGlobal是个没有实现WindowManager的类的,本身定义了套实现。代理
public final class WindowManagerGlobal { private static final String TAG = "WindowManager"; public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { ... } }
大概了解了上述类的分类和各自的做用,那么他们之间如何联系,Window如何建立如何与WindowManager绑定与Activity绑定呢,这个时候就须要一个场景来逐一理解。咱们都知道每个Activity都是与一个Window绑定一块儿的,那么Window的建立以及WindowManager的绑定会不会在建立启动Activity的过程当中就绑定的呢。
对于Activity的启动过程,是有两种,一种是点击程序进入启动的Activity,另外一种而是在已有的Activity中调用startActivity,启动期间经过Binder驱动ActivityWindowService,ActivityThread,ApplicationThread,ActivityStack ,Activity之间进行通讯,为当前Activity建立进程分配任务栈后启动Activity。这里就跳过前面不少步骤,直接到了ActivityThread.handleLaunchActivity去查看Activity的建立
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) { ... // Initialize before creating the activity WindowManagerGlobal.initialize(); Activity a = performLaunchActivity(r, customIntent); if (a != null) { r.createdConfig = new Configuration(mConfiguration); Bundle oldState = r.state; handleResumeActivity(r.token, false, r.isForward, ... }
能够看到 WindowManagerGlobal.initialize()则经过WindowManagerGlobal建立了WindowManagerServer,接下来调用了performLaunchActivity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ... Activity activity = null; try { //Activity经过ClassLoader建立出来 java.lang.ClassLoader cl = r.packageInfo.getClassLoader(); activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); } ... try { //建立Application Application app = r.packageInfo.makeApplication(false, mInstrumentation); ... if (activity != null) { //建立Activity所需的Context Context appContext = createBaseContextForActivity(r, activity); ... //将Context与Activity进行绑定 activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config, r.referrer, r.voiceInteractor); ... //调用activity.oncreate mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); ... //调用Activity的onstart方法 activity.performStart(); //调用activitu的OnRestoreInstanceState方法进行Window数据恢复 mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state, r.persistentState); ... return activity; }
先经过调用 activity = mInstrumentation.newActivity建立Activity,能够看到里面是经过ClassLoader来加载的
public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException { return (Activity)cl.loadClass(className).newInstance(); }
接着建立Activity所需的Application和Context,再调用到activity.attach
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) { //ContextImpl的绑定 attachBaseContext(context); //在当前Activity建立Window mWindow = new PhoneWindow(this); mWindow.setCallback(this); mWindow.setOnWindowDismissedCallback(this); mWindow.getLayoutInflater().setPrivateFactory(this); ... //为Window设置WindowManager mWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), mToken, mComponent.flattenToString(), (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0); if (mParent != null) { mWindow.setContainer(mParent.getWindow()); } //建立完后经过getWindowManager就能够获得WindowManager实例 mWindowManager = mWindow.getWindowManager(); mCurrentConfig = config; }
能够看到在Activity建立到attach的时候,对应的Window窗口也被建立起来,并且Window也与WindowManager绑定。而mWindow,和mWindowManager则是Activity的成员变量。能够看到这里WindiwManager的建立是context.getSystemService(Context.WINDOW_SERVICE)
public void setWindowManager(WindowManager wm, IBinder appToken, String appName, boolean hardwareAccelerated) { ... if (wm == null) { wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); } mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this); }
接着建立WindowManager的实现类,咱们平时在Activity中使用getWindow()和getWindowManager,就是返回对应这两个成员变量。
回到前面那个方法,调用了activity.attach后建立了Window和WindowManager,以后调用了
mInstrumentation.callActivityOnCreate(activity, r.state ...);
该方法则是调用activity.oncreate方法的
public void callActivityOnCreate(Activity activity, Bundle icicle) { prePerformCreate(activity); activity.performCreate(icicle); postPerformCreate(activity); }
final void performCreate(Bundle icicle) { onCreate(icicle); mActivityTransitionState.readState(icicle); performCreateCommon(); }
以后直接调用了
activity.performStart();
来调用activity.onstart()方法
一样以后也调用了
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state...);
看到onRestoreInstanceState是否是很熟悉,没错就是Activity数据恢复调用的方法
public void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState) { activity.performRestoreInstanceState(savedInstanceState); }
final void performRestoreInstanceState(Bundle savedInstanceState) { onRestoreInstanceState(savedInstanceState); restoreManagedDialogs(savedInstanceState); }
里面经过Bundle来保存恢复Window窗口信息
performLaunchActivity调用完后回到handleLaunchActivity
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) { ... //初始化WindowManagerGlobal,为以后addView准备 WindowManagerGlobal.initialize(); Activity a = performLaunchActivity(r, customIntent); if (a != null) { r.createdConfig = new Configuration(mConfiguration); Bundle oldState = r.state; handleResumeActivity(r.token, false, r.isForward, ... }
调用了performLauncherActiviy来建立Activity以及Activity所须要的Context,Window,调用了Activity的onCreate,onStart方法,而接下来调用了handleResumeActivity方法
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) { //调用activity.onResume,把activity数据记录更新到ActivityClientRecord ActivityClientRecord r = performResumeActivity(token, clearHide); if (r != null) { final Activity a = r.activity; //activity.mStartedActivity是用来标记启动Activity,有没有带返回值,通常咱们startActivity(intent)是否默认是startActivityForResult(intent,-1),默认值是-1,因此这里mStartedActivity = false boolean willBeVisible = !a.mStartedActivity; ... //mFinished标记Activity有没有结束,而r.window一开始activity并未赋值给ActivityClientRecord,因此这里为null 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; l.softInputMode |= forwardBit; if (a.mVisibleFromClient) { a.mWindowAdded = true; //把当前的DecorView与WindowManager绑定一块儿 wm.addView(decor, l); } ... if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) { //标记当前的Activity有没有设置新的配置参数,好比如今手机是横屏的,而以后你转成竖屏,那么这里的newCofig就会被赋值,表示参数改变 if (r.newConfig != null) { r.tmpConfig.setTo(r.newConfig); if (r.overrideConfig != null) { r.tmpConfig.updateFrom(r.overrideConfig); } //而后调用这个方法回调,表示屏幕参数发生了改变 performConfigurationChanged(r.activity, r.tmpConfig); ... WindowManager.LayoutParams l = r.window.getAttributes(); ...//改变以后update更新当前窗口的DecorView if (r.activity.mVisibleFromClient) { ViewManager wm = a.getWindowManager(); View decor = r.window.getDecorView(); wm.updateViewLayout(decor, l); } } //参数没改变 r.activity.mVisibleFromServer = true; mNumVisibleActivities++; if (r.activity.mVisibleFromClient) { //因为前面设置了INVASIBLE,因此如今要把DecorView显示出来了 r.activity.makeVisible(); } } //通知ActivityManagerService,Activity完成Resumed ActivityManagerNative.getDefault().activityResumed(token); }
handleResumeActivity方法一开始就调用了activity = performResumeActivity()方法
public final ActivityClientRecord performResumeActivity(IBinder token, boolean clearHide) { ActivityClientRecord r = mActivities.get(token); ... r.activity.mStartedActivity = false; r.activity.onStateNotSaved(); r.activity.mFragments.noteStateNotSaved(); ... //Activity调用onResume,就再也不贴出来了,里面还有判断要不呀奥onReStart,这个想必知道Activity生命周期的人就秒懂了 r.activity.performResume(); ... r.paused = false; r.stopped = false; r.state = null; r.persistentState = null; return r; }
performResumeActivity则是让Activity调用onResume方法,同时把Activity的信息记录在ActivityClientRecord
以后进入到这里这个判断方法。前面代码注释也有说到一些,这里再说详细一点。
boolean willBeVisible = !a.mStartedActivity; 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; l.softInputMode |= forwardBit; if (a.mVisibleFromClient) { a.mWindowAdded = true; //把当前的DecorView与WindowManager绑定一块儿 wm.addView(decor, l); }
r.window一开始null的,activity并无把它的window赋值给它
a.finished表示Activity是否结束
activity.mStartedActivity是用来标记启动Activity需不须要带返回值,通常咱们startActivity(intent)是否默认是startActivityForResult(intent,-1),默认值是-1,因此这里mStartedActivity = false
if (requestCode >= 0) { mStartedActivity = true; }
接着获取当前Activity的Window进而获取到DecorView,再获取当前Activity的WindowManager,将DecorView与WindowManager绑定一块儿。
注意:
这里的DecorView是setContentView以后的DecorView,也就是装载咱们的布局内容的。前面讲到在handleLaucheActivity中,它会先调用performLaunchActivity,再调用handleResumeActivity方法,而在performLaunchActivity方法中先建立Activity对象,接着调用activity.attach方法,来绑定Context,同时在attach中建立了PhoneWindow以及WindowManager,attach以后,就调用了activity.oncreate方法,要知道,咱们的setContentView是放在onCreate方法中的。有看过上一篇setContentView的源码这里应该就会懂。DecorView是PhoneWindow的成员变量,因此setContentView能够说是将DecorView建立添加到Window上面的,调用setContentView后已是把你的布局文件添加到DecorView了。
回到前面,由于是onCreate以后的,因此这里调用
View decor = r.window.getDecorView();
即可以获得当前Activity.Window下的DecorView,接下来经过建立好的WindowManager将DecorView与它绑定到一块儿.
以后到了newConfig参数这里,前面注释已经解释很清楚
if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) { //标记当前的Activity有没有设置新的配置参数,好比如今手机是横屏的,而以后你转成竖屏,那么这里的newCofig就会被赋值,表示参数改变 if (r.newConfig != null) { r.tmpConfig.setTo(r.newConfig); if (r.overrideConfig != null) { r.tmpConfig.updateFrom(r.overrideConfig); } //而后调用这个方法回调,表示屏幕参数发生了改变 performConfigurationChanged(r.activity, r.tmpConfig); ... WindowManager.LayoutParams l = r.window.getAttributes(); ...//改变以后update更新当前窗口的DecorView if (r.activity.mVisibleFromClient) { ViewManager wm = a.getWindowManager(); View decor = r.window.getDecorView(); wm.updateViewLayout(decor, l); } }
这里咱们看下performConfigurationChanged,能够先大胆猜想下这个方法确定是来通知Activity参数改变的一个方法
private static void performConfigurationChanged(ComponentCallbacks2 cb, Configuration config) { Activity activity = (cb instanceof Activity) ? (Activity) cb : null; if (shouldChangeConfig) { cb.onConfigurationChanged(config); ... } }
果真,这里调用到了一个接口回调,注意ComponentCallbacks2这个参数,看它传进来的参数,是r.activity,也就是说Activity里面应该是实现了这个接口,接着经过回调去通知参数更改
public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory2, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks2, Window.OnWindowDismissedCallback {...}
果真如此。
以后来到了最后一步,handleResumeActivity方法里的最后
if (r.activity.mVisibleFromClient) { //因为前面设置了INVASIBLE,因此如今要把DecorView显示出来了 r.activity.makeVisible(); }
要知道,前面咱们的DecorView但是设置了invisible(不知道是否是为了防止更新闪烁的问题),以后多是要把它设置回来,就是在makevisible方法中
void makeVisible() { if (!mWindowAdded) { ViewManager wm = getWindowManager(); wm.addView(mDecor, getWindow().getAttributes()); mWindowAdded = true; } mDecor.setVisibility(View.VISIBLE); }
能够看到若是当前DecorView还未添加到WindwManager的话,则从新添加,最后设置为VISIBLE。
而咱们日常在activity中使用setVisibility,也就是在设置DecorView是VISIBLE仍是INVASIBLE
public void setVisible(boolean visible) { if (mVisibleFromClient != visible) { mVisibleFromClient = visible; if (mVisibleFromServer) { if (visible) makeVisible(); else mDecor.setVisibility(View.INVISIBLE); } } }
至此,Activity被启动起来,视图(DecorView)也被建立(Window)管理(WindowManager)起来了。
Paste_Image.png
在看Window和WindowManager的时候,一直不知道要如何根据源码去学这两个类。结合之前本身学习的状况,以为仍是得根据里面的使用例子,再结合源码起来学,才是最有效的。想到Activity启动会与Window有关,就着手去找,找着找着就越有思路讲。这也算是阅读源码的方法之一吧。
上面把DecorView添加到WindowManager,调用到的是WindowManagerGlobal.addView方法,而
该方法中真正把View传递给WindowManager的是经过ViewRoot的setView()方法,ViewRoot实现了View和WindowManager之间的消息传递。下篇文章将介绍ViewRoot与View和WindowManager之间的联系。
上面有什么口误或者思路不正确的话还麻烦各位读者纠正。
Android窗口机制(四)ViewRootImpl与View和WindowManager:http://www.jianshu.com/p/9da7bfe18374
做者:Hohohong 连接:https://www.jianshu.com/p/6afb0c17df43 来源:简书 简书著做权归做者全部,任何形式的转载都请联系做者得到受权并注明出处。