Android视图加载流程(1)之SetContent( )
关键接口:ViewManager,WindowManager
关键类:Window,WindowManagerImpl,WindowManagerGlobal
关键方法:ActivityThread.performLaunchActivity() ,Activity.attach();
简单介绍
- ViewManager接口定义了一组规则,也就是add、update、remove的操作View接口。
- WindowManager接口除了实现ViewManager接口定义的方法外,还定义一些与窗口显示相关的方法。
- Window为一个抽象类,提供了绘制窗口的一组通用API
- WindowManagerImpl为WindowManager的实现类,一般里面的方法都是具体的实现方法,但它不是!
- WindowManagerGlobal是WindowManagerImpl的具体实现类,类似代理,但没有实现同样的接口,且没有继承关系!☆
ViewManager
public interface ViewManager
{
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}
ViewManagerManager
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
}
WindowManagerImpl
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);
}
}
关系图:
源码解读:
Window是附着于Activity之上的,所以Window的初始化势必与Activity的启动过程有关系!
对于Activity的启动过程,有两种。1. 点击程序进入启动的Activity、2. 已有的Activity中调用startActivty启动。启动期间通过Binder驱动ActivityWindowService,ActivityThread,ApplicationThread,ActivityStack ,Activity之间进行通信,为当前Activity创建进程分配任务栈后启动Activity。
我们直接跳过多个步骤来到与本文章有关系的ActivityThread.handleLaunchActivity去查看Activity的创建
Step1:ActivityThread
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
// 在创建Activity前,初始化
WindowManagerGlobal.initialize();//具体Window的实现类
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward,
...
}
将WindowManagerGlobal进行初始化,启动Activity。
Step2:ActivityThread
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;
}
Step3:Instrumentation
public Activity newActivity(ClassLoader cl, String className,
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return (Activity)cl.loadClass(className).newInstance();
}
调用 activity = mInstrumentation.newActivity创建Activity,可以看到里面是通过ClassLoader来加载
Step3:Activity
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方法中,mWindow = new PhoneWindow(this);
初始化了Window。并通过 mWindow.setWindowManager
将Window于WindowManager进行绑定。且此时mWindow,和mWindowManager成为Activity的成员变量。
Step4:Window
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先判断传入的参数是否为空,为空则通过SystemService获取。最后通过createLocalWindowManager
将Window和WindowManager进行绑定。
Step5: Instrumentation
此时我们返回到Step2的mInstrumentation.callActivityOnCreate(activity, r.state ...);
public void callActivityOnCreate(Activity activity, Bundle icicle) {
prePerformCreate(activity);
activity.performCreate(icicle);
postPerformCreate(activity);
}
此方法调用了Activity的performCreate。且在调用之前和调用之后均有做一定的处理操作。
Step6: Activity
final void performCreate(Bundle icicle) {
onCreate(icicle);//调用熟悉的onCreate
mActivityTransitionState.readState(icicle);
performCreateCommon();
}
这已经是我们非常熟悉的onCreate
了!
Step7: Activity
此时返回到Step2的activity.performStart();
final void performStart() {
...
mInstrumentation.callActivityOnStart(this);//调用onStart
...
}
}
performStart
里调用mInstrumentation
的callActivityOnStart(this)
Step8: Instrumentation
public void callActivityOnStart(Activity activity) {
activity.onStart();//调用熟悉的onStart
}
这已经是我们非常熟悉的onStart
了!
Step9: Instrumentation
此时返回到Step2的activity.callActivityOnRestoreInstanceState();
public void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState) {
activity.performRestoreInstanceState(savedInstanceState);
}
顾名思义,此方法就是在Activity做数据恢复时调用的方法。
Step10: Activity
final void performRestoreInstanceState(Bundle savedInstanceState) {
onRestoreInstanceState(savedInstanceState);
restoreManagedDialogs(savedInstanceState);
}
通过Bundle来保存恢复Window窗口信息,这里就不扩展。
Step11:ActivityThread
此时返回到Step1的handleResumeActivity
,由于此方法的东西比较多,在此我们分成4个部分(Part)
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume) {
//Part01
//调用activity.onResume,把activity数据记录更新到ActivityClientRecord
ActivityClientRecord r = performResumeActivity(token, clearHide);
//Part02
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);//默认设置DecorView不可见
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) {
//Part03
//标记当前的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++;
//Part04
if (r.activity.mVisibleFromClient) {
//由于前面设置了INVASIBLE,所以现在要把DecorView显示出来了
r.activity.makeVisible();
}
}
//通知ActivityManagerService,Activity完成Resumed
ActivityManagerNative.getDefault().activityResumed(token);
}
handleResumeActivity方法一开始就调用了activity = performResumeActivity()方法
Part01
public final ActivityClientRecord performResumeActivity(IBinder token,
boolean clearHide) {
ActivityClientRecord r = mActivities.get(token);
...
r.activity.mStartedActivity = false;
r.activity.onStateNotSaved();
r.activity.mFragments.noteStateNotSaved();
...
r.activity.performResume();//重点调用
...
r.paused = false;
r.stopped = false;
r.state = null;
r.persistentState = null;
return r;
}
让Activity调用onResume,与前几部调用OnCreate和OnStart类似。同时把Activity的信息记录在ActivityClientRecord并返回。
Part02
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);//默认设置DecorView不可见
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,由于还没有复制
- a.mFinished默认为false,a.mFinished表示Activity是否结束
- a.mStartedActivity默认为false,导致willBeVisible默认为true。activity.mStartedActivity是用来标记启动Activity需不需要带返回值,一般我们startActivity(intent)是默认调用startActivityForResult(intent,-1),默认值是-1,所以这里mStartedActivity = false
理解:
if (requestCode >= 0) {
mStartedActivity = true;
}
```java
因为我们现在处于OnResume了,所以DecorView已经创建添加到Window上了(OnCreate调用SetContent)。接着我们将加载好的DecorView与WindowManager通过`wm.addView(decor, l);`绑定在一起。此时的DecorView设置为不可见!
#### Part03
```java
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);
}
}
标志是否有新的配置,如果有的话更新当前窗口的DecorView
Part04
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
如果当前DecorView还未添加到WindwManager的话,则重新添加,最后设置为VISIBLE。此时的DecorView已经显示到屏幕上。
结束 Finish
此时的Activity已经启动,DecorView加载并显示,且与WindowManager进行了绑定。
总结 Summary
当DecorView加载至WindowManager的使用,真正调用的是WindowManagerGlobal.addView()方法。该方法是通过ViewRoot的setView()方法将View传递给WindowManager。ViewRoot实现了View和WindowManager之间的消息传递。
Android视图加载流程(3)之ViewRootImpl的UI刷新机制
PS:本文
整理
自以下文章,若有发现问题请致邮 caoyanglee92@gmail.com
Hohohong Android窗口机制(三)Window和WindowManager的创建与Activity