Android应用程序窗口设计框架介绍
转载:https://blog.****.net/yangwen123/article/details/35987609
在Android系统中,一个Activity对应一个应用程序窗口,任何一个Activity的启动都是由AMS服务和应用程序进程相互配合来完成的。AMS服务统一调度系统中所有进程的Activity启动,而每个Activity的启动过程则由其所属进程来完成。AMS服务通过realStartActivityLocked函数来通知应用程序进程启动某个Activity:
frameworks\base\services\java\com\android\server\am\ ActivityStack.java
-
final boolean realStartActivityLocked(ActivityRecord r,
-
ProcessRecord app, boolean andResume, boolean checkConfig)
-
throws RemoteException {
-
...
-
//系统参数发送变化,通知Activity
-
if (checkConfig) {
-
①Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(mService.mConfiguration,
-
r.mayFreezeScreenLocked(app) ? r.appToken : null);
-
mService.updateConfigurationLocked(config, r, false, false);
-
}
-
//将进程描述符设置到启动的Activity描述符中
-
r.app = app;
-
app.waitingToKill = null;
-
//将启动的Activity添加到进程启动的Activity列表中
-
int idx = app.activities.indexOf(r);
-
if (idx < 0) {
-
app.activities.add(r);
-
}
-
mService.updateLruProcessLocked(app, true, true);
-
try {
-
...
-
//通知应用程序进程加载Activity
-
②app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
-
System.identityHashCode(r), r.info,
-
new Configuration(mService.mConfiguration),
-
r.compat, r.icicle, results, newIntents, !andResume,
-
mService.isNextTransitionForward(), profileFile, profileFd,
-
profileAutoStop);
-
...
-
} catch (RemoteException e) {
-
...
-
}
-
if (mMainStack) {
-
mService.startSetupActivityLocked();
-
}
-
return true;
-
}
AMS通过realStartActivityLocked函数来调度应用程序进程启动一个Activity,参数r为即将启动的Activity在AMS服务中的描述符,参数app为Activity运行所在的应用程序进程在AMS服务中的描述符。函数通过IApplicationThread代理对象ApplicationThreadProxy通知应用程序进程启动r对应的Activity,应用程序进程完成Activity的加载等准备工作后,AMS最后启动该Activity。启动Activity的创建等工作是在应用程序进程中完成的,AMS是通过IApplicationThread接口和应用程序进程通信的。r.appToken 在AMS服务端的类型为Token,是IApplicationToken的Binder本地对象。
frameworks\base\core\java\android\app\ ActivityThread.java
-
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
-
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
-
Bundle state, List<ResultInfo> pendingResults,
-
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
-
String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
-
//将AMS服务传过来的参数封装为ActivityClientRecord对象
-
ActivityClientRecord r = new ActivityClientRecord();
-
r.token = token;
-
r.ident = ident;
-
r.intent = intent;
-
r.activityInfo = info;
-
r.compatInfo = compatInfo;
-
r.state = state;
-
r.pendingResults = pendingResults;
-
r.pendingIntents = pendingNewIntents;
-
r.startsNotResumed = notResumed;
-
r.isForward = isForward;
-
r.profileFile = profileName;
-
r.profileFd = profileFd;
-
r.autoStopProfiler = autoStopProfiler;
-
updatePendingConfiguration(curConfig);
-
//使用异步消息方式实现Activity的启动
-
queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
-
}
参数token从AMS服务端经过Binder传输到应用程序进程后,变为IApplicationToken的Binder代理对象,类型为IApplicationToken.Proxy,这是因为AMS和应用程序运行在不同的进程中。
通过queueOrSendMessage函数将Binder跨进程调用转换为应用程序进程中的异步消息处理
frameworks\base\core\java\android\app\ ActivityThread.java
-
private class H extends Handler {
-
public void handleMessage(Message msg) {
-
switch (msg.what) {
-
case LAUNCH_ACTIVITY: {
-
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
-
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
-
r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);
-
handleLaunchActivity(r, null);
-
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-
} break;
-
}
-
}
-
}
LAUNCH_ACTIVITY消息在应用程序主线程消息循环中得到处理,应用程序通过handleLaunchActivity函数来启动Activity。到此AMS服务就完成了Activity的调度任务,将Activity的启动过程完全交给了应用程序进程来完成。
frameworks\base\core\java\android\app\ ActivityThread.java
-
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
-
//主线程空闲时会定时执行垃圾回收,主线程当前要完成启动Activity的任务,因此这里先暂停GC
-
unscheduleGcIdler();
-
if (r.profileFd != null) {
-
mProfiler.setProfiler(r.profileFile, r.profileFd);
-
mProfiler.startProfiling();
-
mProfiler.autoStopProfiler = r.autoStopProfiler;
-
}
-
// Make sure we are running with the most recent config.
-
①handleConfigurationChanged(null, null);
-
//创建Activity
-
②Activity a = performLaunchActivity(r, customIntent);
-
if (a != null) {
-
r.createdConfig = new Configuration(mConfiguration);
-
Bundle oldState = r.state;
-
//启动Activity
-
③handleResumeActivity(r.token, false, r.isForward);
-
...
-
}else{
-
...
-
}
-
}
performLaunchActivity
应用程序进程通过performLaunchActivity函数将即将要启动的Activity加载到当前进程空间来,同时为启动Activity做准备。
frameworks\base\core\java\android\app\ ActivityThread.java
-
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
-
ActivityInfo aInfo = r.activityInfo;
-
if (r.packageInfo == null) {
-
//通过Activity所在的应用程序信息及该Activity对应的CompatibilityInfo信息从PMS服务中查询当前Activity的包信息
-
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,Context.CONTEXT_INCLUDE_CODE);
-
}
-
//获取当前Activity的组件信息
-
ComponentName component = r.intent.getComponent();
-
if (component == null) {
-
component = r.intent.resolveActivity(mInitialApplication.getPackageManager());
-
r.intent.setComponent(component);
-
}
-
if (r.activityInfo.targetActivity != null) {
-
//packageName为启动Activity的包名,targetActivity为Activity的类名
-
component = new ComponentName(r.activityInfo.packageName,
-
r.activityInfo.targetActivity);
-
}
-
//通过类反射方式加载即将启动的Activity
-
Activity activity = null;
-
try {
-
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
-
①activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
-
StrictMode.incrementExpectedActivityCount(activity.getClass());
-
r.intent.setExtrasClassLoader(cl);
-
if (r.state != null) {
-
r.state.setClassLoader(cl);
-
}
-
} catch (Exception e) {
-
...
-
}
-
try {
-
//通过单例模式为应用程序进程创建Application对象
-
②Application app = r.packageInfo.makeApplication(false, mInstrumentation);
-
if (activity != null) {
-
//为当前Activity创建上下文对象ContextImpl
-
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(mCompatConfiguration);
-
//将当前启动的Activity和上下文ContextImpl、Application绑定
-
④activity.attach(appContext, this, getInstrumentation(), r.token,
-
r.ident, app, r.intent, r.activityInfo, title, r.parent,
-
r.embeddedID, r.lastNonConfigurationInstances, config);
-
...
-
//调用Activity的OnCreate函数
-
⑤mInstrumentation.callActivityOnCreate(activity, r.state);
-
...
-
//将Activity保存到ActivityClientRecord中,ActivityClientRecord为Activity在应用程序进程中的描述符
-
r.activity = activity;
-
...
-
}
-
r.paused = true;
-
//ActivityThread的成员变量mActivities保存了当前应用程序进程中的所有Activity的描述符
-
mActivities.put(r.token, r);
-
} catch (SuperNotCalledException e) {
-
...
-
}
-
return activity;
-
}
在该函数中,首先通过PMS服务查找到即将启动的Activity的包名信息,然后通过类反射方式创建一个该Activity实例,同时为应用程序启动的每一个Activity创建一个LoadedApk实例对象,应用程序进程中创建的所有LoadedApk对象保存在ActivityThread的成员变量mPackages中。接着通过LoadedApk对象的makeApplication函数,使用单例模式创建Application对象,因此在android应用程序进程中有且只有一个Application实例。然后为当前启动的Activity创建一个ContextImpl上下文对象,并初始化该上下文,到此我们可以知道,启动一个Activity需要以下对象:
1) XXActivity对象,需要启动的Activity;
2) LoadedApk对象,每个启动的Activity都拥有属于自身的LoadedApk对象;
3) ContextImpl对象,每个启动的Activity都拥有属于自身的ContextImpl对象;
4) Application对象,应用程序进程中有且只有一个实例,和Activity是一对多的关系;
加载Activity类
-
public Activity newActivity(ClassLoader cl, String className,
-
Intent intent)
-
throws InstantiationException, IllegalAccessException,
-
ClassNotFoundException {
-
return (Activity)cl.loadClass(className).newInstance();
-
}
这里通过类反射的方式来加载要启动的Activity实例对象。
LoadedApk构造过程
首先介绍一下LoadedApk对象的构造过程:
frameworks\base\core\java\android\app\ ActivityThread.java
-
public final LoadedApk getPackageInfo(String packageName, CompatibilityInfo compatInfo,
-
int flags) {
-
synchronized (mPackages) {
-
//通过Activity的包名从对应的成员变量中查找LoadedApk对象
-
WeakReference<LoadedApk> ref;
-
if ((flags&Context.CONTEXT_INCLUDE_CODE) != 0) {
-
ref = mPackages.get(packageName);
-
} else {
-
ref = mResourcePackages.get(packageName);
-
}
-
LoadedApk packageInfo = ref != null ? ref.get() : null;
-
if (packageInfo != null && (packageInfo.mResources == null
-
|| packageInfo.mResources.getAssets().isUpToDate())) {
-
...
-
return packageInfo;
-
}
-
}
-
//如果没有,则为当前Activity创建对应的LoadedApk对象
-
ApplicationInfo ai = null;
-
try {
-
//通过包名在PMS服务中查找应用程序信息
-
ai = getPackageManager().getApplicationInfo(packageName,
-
PackageManager.GET_SHARED_LIBRARY_FILES, UserId.myUserId());
-
} catch (RemoteException e) {
-
// Ignore
-
}
-
//使用另一个重载函数创建LoadedApk对象
-
if (ai != null) {
-
return getPackageInfo(ai, compatInfo, flags);
-
}
-
return null;
-
}
-
public final LoadedApk getPackageInfo(ApplicationInfo ai, CompatibilityInfo compatInfo,
-
int flags) {
-
boolean includeCode = (flags&Context.CONTEXT_INCLUDE_CODE) != 0;
-
boolean securityViolation = includeCode && ai.uid != 0
-
&& ai.uid != Process.SYSTEM_UID && (mBoundApplication != null
-
? !UserId.isSameApp(ai.uid, mBoundApplication.appInfo.uid)
-
: true);
-
if ((flags&(Context.CONTEXT_INCLUDE_CODE|Context.CONTEXT_IGNORE_SECURITY))
-
== Context.CONTEXT_INCLUDE_CODE) {
-
...
-
}
-
return getPackageInfo(ai, compatInfo, null, securityViolation, includeCode);
-
}
-
private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
-
ClassLoader baseLoader, boolean securityViolation, boolean includeCode) {
-
//再次从对应的成员变量中查找LoadedApk实例
-
synchronized (mPackages) {
-
WeakReference<LoadedApk> ref;
-
if (includeCode) {
-
ref = mPackages.get(aInfo.packageName);
-
} else {
-
ref = mResourcePackages.get(aInfo.packageName);
-
}
-
LoadedApk packageInfo = ref != null ? ref.get() : null;
-
if (packageInfo == null || (packageInfo.mResources != null
-
&& !packageInfo.mResources.getAssets().isUpToDate())) {
-
...
-
//构造一个LoadedApk对象
-
packageInfo =new LoadedApk(this, aInfo, compatInfo, this, baseLoader,
-
securityViolation, includeCode &&
-
(aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0);
-
//保存LoadedApk实例到ActivityThread的相应成员变量中
-
if (includeCode) {
-
mPackages.put(aInfo.packageName,
-
new WeakReference<LoadedApk>(packageInfo));
-
} else {
-
mResourcePackages.put(aInfo.packageName,
-
new WeakReference<LoadedApk>(packageInfo));
-
}
-
}
-
return packageInfo;
-
}
-
}
frameworks\base\core\java\android\app\LoadedApk.java
-
public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo,
-
CompatibilityInfo compatInfo,
-
ActivityThread mainThread, ClassLoader baseLoader,
-
boolean securityViolation, boolean includeCode) {
-
mActivityThread = activityThread;
-
mApplicationInfo = aInfo;
-
mPackageName = aInfo.packageName;
-
mAppDir = aInfo.sourceDir;
-
final int myUid = Process.myUid();
-
mResDir = aInfo.uid == myUid ? aInfo.sourceDir
-
: aInfo.publicSourceDir;
-
if (!UserId.isSameUser(aInfo.uid, myUid) && !Process.isIsolated()) {
-
aInfo.dataDir = PackageManager.getDataDirForUser(UserId.getUserId(myUid),
-
mPackageName);
-
}
-
mSharedLibraries = aInfo.sharedLibraryFiles;
-
mDataDir = aInfo.dataDir;
-
mDataDirFile = mDataDir != null ? new File(mDataDir) : null;
-
mLibDir = aInfo.nativeLibraryDir;
-
mBaseClassLoader = baseLoader;
-
mSecurityViolation = securityViolation;
-
mIncludeCode = includeCode;
-
mCompatibilityInfo.set(compatInfo);
-
if (mAppDir == null) {
-
//为应用程序进程创建一个ContextImpl上下文
-
if (ActivityThread.mSystemContext == null) {
-
ActivityThread.mSystemContext =
-
ContextImpl.createSystemContext(mainThread);
-
ActivityThread.mSystemContext.getResources().updateConfiguration(
-
mainThread.getConfiguration(),
-
mainThread.getDisplayMetricsLocked(compatInfo, false),
-
compatInfo);
-
}
-
mClassLoader = ActivityThread.mSystemContext.getClassLoader();
-
mResources = ActivityThread.mSystemContext.getResources();
-
}
-
}
从以上LoadedApk的构造函数可以看出,LoadedApk类记录了Activity运行所在的ActivityThread、Activity所在的应用程序信息、Activity的包名、Activity的资源路径、Activity的库路径、Activity的数据存储路径、类加载器和应用程序所使用的资源等信息。
Application构造过程
当Activity为应用程序进程启动的第一个Activity,因此需要构造一个Application对象
frameworks\base\core\java\android\app\LoadedApk.java
-
public Application makeApplication(boolean forceDefaultAppClass,
-
Instrumentation instrumentation) {
-
//在应用程序进程空间以单例模式创建Application对象
-
if (mApplication != null) {
-
return mApplication;
-
}
-
Application app = null;
-
//得到应用程序的Application类名
-
String appClass = mApplicationInfo.className;
-
//如果应用程序没用重写Application,则使用Android默认的Application类
-
if (forceDefaultAppClass || (appClass == null)) {
-
appClass = "android.app.Application";
-
}
-
try {
-
java.lang.ClassLoader cl = getClassLoader();
-
//为Application实例创建一个上下文对象ContextImpl
-
①ContextImpl appContext = new ContextImpl();
-
//初始化上下文
-
②appContext.init(this, null, mActivityThread);
-
//创建Application实例对象
-
③app = mActivityThread.mInstrumentation.newApplication(
-
cl, appClass, appContext);
-
appContext.setOuterContext(app);
-
} catch (Exception e) {
-
...
-
}
-
mActivityThread.mAllApplications.add(app);
-
mApplication = app;
-
if (instrumentation != null) {
-
try {
-
//调用Application的OnCreate函数
-
④instrumentation.callApplicationOnCreate(app);
-
} catch (Exception e) {
-
...
-
}
-
}
-
return app;
-
}
在应用程序开发过程中,当我们重写了Application类后,应用程序加载运行的是我们定义的Application类,否则就加载运行默认的Application类。从Application对象的构造过程就可以解释为什么应用程序启动后首先执行的是Application的OnCreate函数。在实例化Application对象时,同样创建并初始化了一个ContextImpl上下文对象。
ContextImpl构造过程
前面我们介绍了,每一个Activity拥有一个上下文对象ContextImpl,每一个Application对象也拥有一个ContextImpl上下文对象,那么ContextImpl对象又是如何构造的呢?
frameworks\base\core\java\android\app\ ContextImpl.java
-
ContextImpl() {
-
mOuterContext = this;
-
}
ContextImpl的构造过程什么也没干,通过调用ContextImpl的init函数进行初始化
-
final void init(LoadedApk packageInfo,IBinder activityToken, ActivityThread mainThread) {
-
init(packageInfo, activityToken, mainThread, null, null);
-
}
-
final void init(LoadedApk packageInfo,IBinder activityToken, ActivityThread mainThread,
-
Resources container, String basePackageName) {
-
mPackageInfo = packageInfo;
-
mBasePackageName = basePackageName != null ? basePackageName : packageInfo.mPackageName;
-
mResources = mPackageInfo.getResources(mainThread);
-
if (mResources != null && container != null
-
&& container.getCompatibilityInfo().applicationScale !=
-
mResources.getCompatibilityInfo().applicationScale) {
-
mResources = mainThread.getTopLevelResources(
-
mPackageInfo.getResDir(), container.getCompatibilityInfo());
-
}
-
mMainThread = mainThread;
-
mContentResolver = new ApplicationContentResolver(this, mainThread);
-
setActivityToken(activityToken);
-
}
从ContextImpl的初始化函数中可以知道,ContextImpl记录了应用程序的包名信息、应用程序的资源信息、应用程序的主线程、ContentResolver及Activity对应的IApplicationToken.Proxy,当然对应Application对象所拥有的ContextImpl上下文就没有对应的Token了。通过前面的分析我们可以知道各个对象之间的关系:
对象Attach过程
Activity所需要的对象都创建好了,就需要将Activity和Application对象、ContextImpl对象绑定在一起。
frameworks\base\core\java\android\app\ Activity.java
-
final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token,
-
Application application, Intent intent, ActivityInfo info, CharSequence title,
-
Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances,
-
Configuration config) {
-
attach(context, aThread, instr, token, 0, application, intent, info, title, parent, id,
-
lastNonConfigurationInstances, config);
-
}
context:Activity的上下文对象,就是前面创建的ContextImpl对象;
aThread:Activity运行所在的主线程描述符ActivityThread;
instr:用于监控Activity运行状态的Instrumentation对象;
token:用于和AMS服务通信的IApplicationToken.Proxy代理对象;
application:Activity运行所在进程的Application对象;
parent:启动当前Activity的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) {
-
//将上下文对象ContextImpl保存到Activity的成员变量中
-
attachBaseContext(context);
-
//每个Activity都拥有一个FragmentManager,这里就是将当前Activity设置到FragmentManager中管理
-
mFragments.attachActivity(this);
-
//创建窗口对象
-
①mWindow = PolicyManager.makeNewWindow(this);
-
mWindow.setCallback(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);
-
}
-
//记录应用程序的UI线程
-
mUiThread = Thread.currentThread();
-
//记录应用程序的ActivityThread对象
-
mMainThread = aThread;
-
mInstrumentation = instr;
-
mToken = token;
-
mIdent = ident;
-
mApplication = application;
-
mIntent = intent;
-
mComponent = intent.getComponent();
-
mActivityInfo = info;
-
mTitle = title;
-
mParent = parent;
-
mEmbeddedID = id;
-
mLastNonConfigurationInstances = lastNonConfigurationInstances;
-
//为Activity所在的窗口创建窗口管理器
-
②mWindow.setWindowManager(null, mToken, mComponent.flattenToString(),
-
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
-
if (mParent != null) {
-
mWindow.setContainer(mParent.getWindow());
-
}
-
mWindowManager = mWindow.getWindowManager();
-
mCurrentConfig = config;
-
}
在该attach函数中主要做了以下几件事:
1) 将Activity设置到FragmentManager中;
2) 根据参数初始化Activity的成员变量;
3) 为Activity创建窗口Window对象;
4) 为Window创建窗口管理器;
到此为止应用程序进程为启动的Activity对象创建了以下不同的实例对象,它们之间的关系如下:
应用程序窗口创建过程
frameworks\base\core\java\com\android\internal\policy\ PolicyManager.java
-
public static Window makeNewWindow(Context context) {
-
return sPolicy.makeNewWindow(context);
-
}
通过Policy类的makeNewWindow函数来创建一个应用程序窗口
-
private static final String POLICY_IMPL_CLASS_NAME =
-
"com.android.internal.policy.impl.Policy";
-
private static final IPolicy sPolicy;
-
static {
-
try {
-
Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
-
sPolicy = (IPolicy)policyClass.newInstance();
-
} catch (ClassNotFoundException ex) {
-
...
-
}
-
}
frameworks\base\policy\src\com\android\internal\policy\impl\ Policy.java
-
public Window makeNewWindow(Context context) {
-
return new PhoneWindow(context);
-
}
应用程序窗口的创建过程其实就是构造一个PhoneWindow对象。PhoneWindow类是通过静态方式加载到应用程序进程空间的。
-
private static final String[] preload_classes = {
-
"com.android.internal.policy.impl.PhoneLayoutInflater",
-
"com.android.internal.policy.impl.PhoneWindow",
-
"com.android.internal.policy.impl.PhoneWindow$1",
-
"com.android.internal.policy.impl.PhoneWindow$ContextMenuCallback",
-
"com.android.internal.policy.impl.PhoneWindow$DecorView",
-
"com.android.internal.policy.impl.PhoneWindow$PanelFeatureState",
-
"com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState",
-
};
-
static {
-
for (String s : preload_classes) {
-
try {
-
Class.forName(s);
-
} catch (ClassNotFoundException ex) {
-
Log.e(TAG, "Could not preload class for phone policy: " + s);
-
}
-
}
-
}
PhoneWindow的构造过程
-
public PhoneWindow(Context context) {
-
super(context);
-
mAlternativePanelStyle=getContext().getResources().getBoolean(com.android.internal.R.bool.config_alternativePanelStyle);
-
mLayoutInflater = LayoutInflater.from(context);
-
}
构造过程比较简单,只是得到布局加载服务对象。
窗口管理器创建过程
通过前面的分析我们可以知道,在Activity启动过程中,会为Activity创建一个窗口对象PhoneWindow,应用程序有了窗口那就需要有一个窗口管理器来管理这些窗口,因此在Activity启动过程中还会创建一个WindowManager对象。
frameworks\base\core\java\android\view\ Window.java
-
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
-
boolean hardwareAccelerated) {
-
mAppToken = appToken;// IApplicationToken.Proxy代理对象
-
mAppName = appName;
-
//得到WindowManagerImpl实例,
-
if (wm == null) {
-
wm = WindowManagerImpl.getDefault();
-
}
-
//为每个启动的Activity创建一个轻量级的窗口管理器LocalWindowManager
-
mWindowManager = new LocalWindowManager(wm, hardwareAccelerated);
-
}
WindowManagerImpl为重量级的窗口管理器,应用程序进程中有且只有一个WindowManagerImpl实例,它管理了应用程序进程中创建的所有PhoneWindow窗口。Activity并没有直接引用WindowManagerImpl实例,Android系统为每一个启动的Activity创建了一个轻量级的窗口管理器LocalWindowManager,每个Activity通过LocalWindowManager来访问WindowManagerImpl,它们三者之间的关系如下图所示:
WindowManagerImpl以单例模式创建,应用程序进程中有且只有一个WindowManagerImpl实例
frameworks\base\core\java\android\view\ WindowManagerImpl.java
-
private final static WindowManagerImpl sWindowManager = new WindowManagerImpl();
-
public static WindowManagerImpl getDefault() {
-
return sWindowManager;
-
}
应用程序进程会为每一个Activity创建一个LocalWindowManager实例对象
frameworks\base\core\java\android\view\ Window.java
-
LocalWindowManager(WindowManager wm, boolean hardwareAccelerated) {
-
super(wm, getCompatInfo(mContext));
-
mHardwareAccelerated = hardwareAccelerated ||
-
SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
-
}
frameworks\base\core\java\android\view\ WindowManagerImpl.java
-
CompatModeWrapper(WindowManager wm, CompatibilityInfoHolder ci) {
-
mWindowManager = wm instanceof CompatModeWrapper
-
? ((CompatModeWrapper)wm).mWindowManager : (WindowManagerImpl)wm;
-
if (ci == null) {
-
mDefaultDisplay = mWindowManager.getDefaultDisplay();
-
} else {
-
mDefaultDisplay = Display.createCompatibleDisplay(
-
mWindowManager.getDefaultDisplay().getDisplayId(), ci);
-
}
-
mCompatibilityInfo = ci;
-
}
-
public Display getDefaultDisplay() {
-
return new Display(Display.DEFAULT_DISPLAY, null);
-
}
frameworks\base\core\java\android\view\Display.java
-
Display(int display, CompatibilityInfoHolder compatInfo) {
-
synchronized (sStaticInit) {
-
if (!sInitialized) {
-
nativeClassInit();
-
sInitialized = true;
-
}
-
}
-
mCompatibilityInfo = compatInfo != null ? compatInfo : new CompatibilityInfoHolder();
-
mDisplay = display;
-
init(display);
-
}
构造Display对象时需要初始化该对象。
frameworks\base\core\jni\android_view_Display.cpp
-
static void android_view_Display_init(
-
JNIEnv* env, jobject clazz, jint dpy)
-
{
-
DisplayInfo info;
-
if (headless) {
-
// initialize dummy display with reasonable values
-
info.pixelFormatInfo.format = 1; // RGB_8888
-
info.fps = 60;
-
info.density = 160;
-
info.xdpi = 160;
-
info.ydpi = 160;
-
} else {
-
status_t err = SurfaceComposerClient::getDisplayInfo(DisplayID(dpy), &info);
-
if (err < 0) {
-
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-
return;
-
}
-
}
-
env->SetIntField(clazz, offsets.pixelFormat,info.pixelFormatInfo.format);
-
env->SetFloatField(clazz, offsets.fps, info.fps);
-
env->SetFloatField(clazz, offsets.density, info.density);
-
env->SetFloatField(clazz, offsets.xdpi, info.xdpi);
-
env->SetFloatField(clazz, offsets.ydpi, info.ydpi);
-
}
Display的初始化过程很简单,就是通过SurfaceComposerClient请求SurfaceFlinger得到显示屏的基本信息。
frameworks\native\libs\gui\ SurfaceComposerClient.cpp
-
status_t SurfaceComposerClient::getDisplayInfo(
-
DisplayID dpy, DisplayInfo* info)
-
{
-
if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
-
return BAD_VALUE;
-
volatile surface_flinger_cblk_t const * cblk = get_cblk();
-
volatile display_cblk_t const * dcblk = cblk->displays + dpy;
-
info->w = dcblk->w;
-
info->h = dcblk->h;
-
info->orientation = dcblk->orientation;
-
info->xdpi = dcblk->xdpi;
-
info->ydpi = dcblk->ydpi;
-
info->fps = dcblk->fps;
-
info->density = dcblk->density;
-
return getPixelFormatInfo(dcblk->format, &(info->pixelFormatInfo));
-
}
我们知道在SurfaceFlinger启动过程中,创建了一块匿名共享内存来保存显示屏的基本信息,这里就是通过访问这块匿名共享内存来读取显示屏信息。到此一个Activity所需要的窗口对象就创建完成了,在应用程序窗口的创建过程中一共创建了以下几个对象:
Activity视图对象的创建过程
在Activity的attach函数中完成应用程序窗口的创建后,通过Instrumentation回调Activity的OnCreate函数来为当前Activity加载布局文件,进一步创建视图对象。
frameworks\base\core\java\android\app\Instrumentation.java
-
public void callActivityOnCreate(Activity activity, Bundle icicle) {
-
...
-
activity.performCreate(icicle);
-
...
-
}
frameworks\base\core\java\android\app\Activity.java
-
final void performCreate(Bundle icicle) {
-
onCreate(icicle);
-
mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
-
com.android.internal.R.styleable.Window_windowNoDisplay, false);
-
mFragments.dispatchActivityCreated();
-
}
我们知道在应用程序开发中,需要重写Activity的OnCreate函数:
Packages\apps\xxx\src\com\xxx\ xxxActivity.java
-
public void onCreate(Bundle savedInstanceState) {
-
super.onCreate(savedInstanceState);
-
setContentView(R.layout.main_activity);
-
...
-
}
在OnCreate函数中通过setContentView来设置Activity的布局文件,就是生成该Activity的所有视图对象。
frameworks\base\core\java\android\app\Activity.java
-
public void setContentView(View view, ViewGroup.LayoutParams params) {
-
getWindow().setContentView(view, params);
-
//初始化动作条
-
initActionBar();
-
}
getWindow()函数得到前面创建的窗口对象PhoneWindow,通过PhoneWindow来设置Activity的视图。
frameworks\base\policy\src\com\android\internal\policy\impl\PhoneWindow.java
-
public void setContentView(int layoutResID) {
-
//如果窗口顶级视图对象为空,则创建窗口视图对象
-
if (mContentParent == null) {
-
installDecor();
-
} else {//否则只是移除该视图对象中的其他视图
-
mContentParent.removeAllViews();
-
}
-
//加载布局文件,并将布局文件中的所有视图对象添加到mContentParent容器中
-
mLayoutInflater.inflate(layoutResID, mContentParent);
-
final Callback cb = getCallback();
-
if (cb != null && !isDestroyed()) {
-
cb.onContentChanged();
-
}
-
}
PhoneWindow的成员变量mContentParent的类型为ViewGroup,是窗口内容存放的地方
frameworks\base\policy\src\com\android\internal\policy\impl\PhoneWindow.java
-
private void installDecor() {
-
if (mDecor == null) {
-
①mDecor = generateDecor();
-
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
-
mDecor.setIsRootNamespace(true);
-
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
-
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
-
}
-
}
-
if (mContentParent == null) {
-
②mContentParent = generateLayout(mDecor);
-
mDecor.makeOptionalFitsSystemWindows();
-
//应用程序窗口标题栏
-
mTitleView = (TextView)findViewById(com.android.internal.R.id.title);
-
if (mTitleView != null) {
-
...
-
} else {
-
//应用程序窗口动作条
-
mActionBar = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
-
if (mActionBar != null) {
-
...
-
}
-
}
-
}
-
}
通过函数generateDecor()来创建一个DecorView对象
-
protected DecorView generateDecor() {
-
return new DecorView(getContext(), -1);
-
}
接着通过generateLayout(mDecor)来创建视图对象容器mContentParent
-
protected ViewGroup generateLayout(DecorView decor) {
-
//通过读取属性配置文件设置窗口风格
-
if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionBarOverlay, false)) {
-
requestFeature(FEATURE_ACTION_BAR_OVERLAY);
-
}
-
...
-
//通过读取属性配置文件设置窗口标志
-
if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) {
-
setFlags(FLAG_FULLSCREEN,FLAG_FULLSCREEN&(~getForcedWindowFlags()));
-
}
-
...
-
WindowManager.LayoutParams params = getAttributes();
-
...
-
mDecor.startChanging();
-
//根据窗口主题风格选择不同的布局文件layoutResource
-
...
-
//加载布局文件
-
①View in = mLayoutInflater.inflate(layoutResource, null);
-
//添加到DecorView中
-
②decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
-
//从窗口视图中找出窗口内容视图对象
-
③ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
-
...
-
mDecor.finishChanging();
-
return contentParent;
-
}
到此Activity的所有视图对象都已经创建完毕,DecorView是Activity的顶级视图,由窗口PhoneWindow对象持有,在DecorView视图对象中添加了一个ViewGroup容器组件contentParent,所有用户定义视图组件将被添加到该容器中。
handleResumeActivity
performLaunchActivity函数完成了两件事:
1) Activity窗口对象的创建,通过attach函数来完成;
2) Activity视图对象的创建,通过setContentView函数来完成;
这些准备工作完成后,就可以显示该Activity了,应用程序进程通过调用handleResumeActivity函数来启动Activity的显示过程。
frameworks\base\core\java\android\app\ ActivityThread.java
-
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
-
unscheduleGcIdler();
-
ActivityClientRecord r;
-
try {
-
①r = performResumeActivity(token, clearHide);
-
} catch (Exception e) {
-
...
-
}
-
if (r != null) {
-
final Activity a = r.activity;
-
...
-
if (r.window == null && !a.mFinished && willBeVisible) {
-
//获得为当前Activity创建的窗口PhoneWindow对象
-
r.window = r.activity.getWindow();
-
//获取为窗口创建的视图DecorView对象
-
View decor = r.window.getDecorView();
-
decor.setVisibility(View.INVISIBLE);
-
//在attach函数中就为当前Activity创建了WindowManager对象
-
ViewManager wm = a.getWindowManager();
-
//得到该视图对象的布局参数
-
②WindowManager.LayoutParams l = r.window.getAttributes();
-
//将视图对象保存到Activity的成员变量mDecor中
-
a.mDecor = decor;
-
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-
if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
-
l.idleScreenAvailable = true;
-
} else {
-
l.idleScreenAvailable = false;
-
}
-
l.softInputMode |= forwardBit;
-
if (a.mVisibleFromClient) {
-
a.mWindowAdded = true;
-
//将创建的视图对象DecorView添加到Activity的窗口管理器中
-
③wm.addView(decor, l);
-
}
-
} else if (!willBeVisible) {
-
...
-
}
-
...
-
if (!r.onlyLocalRequest) {
-
r.nextIdle = mNewActivities;
-
mNewActivities = r;
-
Looper.myQueue().addIdleHandler(new Idler());
-
}
-
...
-
} else {
-
...
-
}
-
}
我们知道,在前面的performLaunchActivity函数中完成Activity的创建后,会将当前当前创建的Activity在应用程序进程端的描述符ActivityClientRecord以键值对的形式保存到ActivityThread的成员变量mActivities中:mActivities.put(r.token, r),r.token就是Activity的身份证,即是IApplicationToken.Proxy代理对象,也用于与AMS通信。上面的函数首先通过performResumeActivity从mActivities变量中取出Activity的应用程序端描述符ActivityClientRecord,然后取出前面为Activity创建的视图对象DecorView和窗口管理器WindowManager,最后将视图对象添加到窗口管理器中。
我们知道Activity引用的其实是轻量级的窗口管理器LocalWindowManager
frameworks\base\core\java\android\view\ Window.java
-
public final void addView(View view, ViewGroup.LayoutParams params) {
-
WindowManager.LayoutParams wp = (WindowManager.LayoutParams)params;
-
CharSequence curTitle = wp.getTitle();
-
//应用程序窗口
-
if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
-
wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
-
if (wp.token == null) {
-
View decor = peekDecorView();
-
if (decor != null) {
-
// LayoutParams 的token设置为W本地Binder对象
-
wp.token = decor.getWindowToken();
-
}
-
}
-
if (curTitle == null || curTitle.length() == 0) {
-
//根据窗口类型设置不同的标题
-
…
-
if (mAppName != null) {
-
title += ":" + mAppName;
-
}
-
wp.setTitle(title);
-
}
-
} else {//系统窗口
-
if (wp.token == null) {
-
wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
-
}
-
if ((curTitle == null || curTitle.length() == 0)
-
&& mAppName != null) {
-
wp.setTitle(mAppName);
-
}
-
}
-
if (wp.packageName == null) {
-
wp.packageName = mContext.getPackageName();
-
}
-
if (mHardwareAccelerated) {
-
wp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-
}
-
super.addView(view, params);
-
}
LocalWindowManager的addView函数对不同类型窗口的布局参数进行相应的设置,比如布局参数中的token设置,如果是应用程序窗口,则设置token为W本地Binder对象。如果不是应用程序窗口,同时当前窗口没有父窗口,则设置token为当前窗口的IApplicationToken.Proxy代理对象,否则设置为父窗口的IApplicationToken.Proxy代理对象。最后视图组件的添加工作交给其父类来完成。LocalWindowManager继承于CompatModeWrapper,是WindowManagerImpl的内部类。
frameworks\base\core\java\android\view\WindowManagerImpl.java
-
public void addView(View view, android.view.ViewGroup.LayoutParams params) {
-
mWindowManager.addView(view, params, mCompatibilityInfo);
-
}
前面我们介绍了,每一个Activity拥有一个轻量级窗口管理器,通过轻量级窗口管理器LocalWindowManager来访问重量级窗口管理器WindowManagerImpl,因此视图组件的添加过程又转交给了WindowManagerImpl来实现。
-
public void addView(View view, ViewGroup.LayoutParams params, CompatibilityInfoHolder cih) {
-
addView(view, params, cih, false);
-
}
该函数又调用WindowManagerImpl的另一个重载函数来添加视图组件
-
private void addView(View view, ViewGroup.LayoutParams params,
-
CompatibilityInfoHolder cih, boolean nest) {
-
...
-
final WindowManager.LayoutParams wparams= (WindowManager.LayoutParams)params;
-
ViewRootImpl root;
-
View panelParentView = null;
-
synchronized (this) {
-
...
-
//从mViews中查找当前添加的View
-
int index = findViewLocked(view, false);
-
//如果已经存在,直接返回
-
if (index >= 0) {
-
...
-
return;
-
}
-
//尚未添加当前View
-
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];
-
}
-
}
-
}
-
//为Activity创建一个ViewRootImpl对象
-
①root = new ViewRootImpl(view.getContext());
-
...
-
//设置视图组件的布局参数
-
view.setLayoutParams(wparams);
-
if (mViews == null) {
-
index = 1;
-
mViews = new View[1];
-
mRoots = new ViewRootImpl[1];
-
mParams = new WindowManager.LayoutParams[1];
-
} else {
-
//动态增加mViews数组长度
-
index = mViews.length + 1;
-
Object[] old = mViews;
-
mViews = new View[index];
-
System.arraycopy(old, 0, mViews, 0, index-1);
-
//动态增加mRoots数组长度
-
old = mRoots;
-
mRoots = new ViewRootImpl[index];
-
System.arraycopy(old, 0, mRoots, 0, index-1);
-
//动态增加mParams数组长度
-
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;
-
}
-
try {
-
③root.setView(view, wparams, panelParentView);
-
} catch (RuntimeException e) {
-
...
-
}
-
}
到此我们知道,当应用程序向窗口管理器中添加一个视图对象时,首先会为该视图对象创建一个ViewRootImpl对象,并且将视图对象、ViewRootImpl对象、视图布局参数分别保存到窗口管理器WindowManagerImpl得mViews、mRoots、mParams数组中,如下图所示:
最后通过ViewRootImpl对象来完成视图的显示过程。
ViewRootImpl构造过程
frameworks\base\core\java\android\view\ViewRootImpl.java
-
public ViewRootImpl(Context context) {
-
...
-
①getWindowSession(context.getMainLooper());
-
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);
-
mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
-
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;
-
mAccessibilityManager = AccessibilityManager.getInstance(context);
-
mAccessibilityInteractionConnectionManager =
-
new AccessibilityInteractionConnectionManager();
-
mAccessibilityManager.addAccessibilityStateChangeListener(
-
mAccessibilityInteractionConnectionManager);
-
③mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, mHandler, this);
-
mViewConfiguration = ViewConfiguration.get(context);
-
mDensity = context.getResources().getDisplayMetrics().densityDpi;
-
mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
-
mProfileRendering = Boolean.parseBoolean(
-
SystemProperties.get(PROPERTY_PROFILE_RENDERING, "false"));
-
④mChoreographer = Choreographer.getInstance();
-
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-
mAttachInfo.mScreenOn = powerManager.isScreenOn();
-
loadSystemProperties();
-
}
在ViewRootImpl的构造函数中初始化了一些成员变量,ViewRootImpl创建了以下几个主要对象:
1) 通过getWindowSession(context.getMainLooper())得到IWindowSession的代理对象,该对象用于和WMS通信。
2) 创建了一个W本地Binder对象,用于WMS通知应用程序进程。
3) 采用单例模式创建了一个Choreographer对象,用于统一调度窗口绘图。
4) 创建ViewRootHandler对象,用于处理当前视图消息。
5) 构造一个AttachInfo对象;
6) 创建Surface对象,用于绘制当前视图,当然该Surface对象的真正创建是由WMS来完成的,只不过是WMS传递给应用程序进程的。
-
private final Surface mSurface = new Surface();
-
final ViewRootHandler mHandler = new ViewRootHandler();
IWindowSession代理获取过程
frameworks\base\core\java\android\view\ViewRootImpl.java
-
public static IWindowSession getWindowSession(Looper mainLooper) {
-
synchronized (mStaticInit) {
-
if (!mInitialized) {
-
try {
-
//获取输入法管理器
-
InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
-
//获取窗口管理器
-
IWindowManager windowManager = Display.getWindowManager();
-
//得到IWindowSession代理对象
-
sWindowSession = windowManager.openSession(imm.getClient(), imm.getInputContext());
-
float animatorScale = windowManager.getAnimationScale(2);
-
ValueAnimator.setDurationScale(animatorScale);
-
mInitialized = true;
-
} catch (RemoteException e) {
-
}
-
}
-
return sWindowSession;
-
}
-
}
以上函数通过WMS的openSession函数创建应用程序与WMS之间的连接通道,即获取IWindowSession代理对象,并将该代理对象保存到ViewRootImpl的静态成员变量sWindowSession中
static IWindowSession sWindowSession;
因此在应用程序进程中有且只有一个IWindowSession代理对象。
frameworks\base\services\java\com\android\server\wm\WindowManagerService.java
-
public IWindowSession openSession(IInputMethodClient client,
-
IInputContext inputContext) {
-
if (client == null) throw new IllegalArgumentException("null client");
-
if (inputContext == null) throw new IllegalArgumentException("null inputContext");
-
Session session = new Session(this, client, inputContext);
-
return session;
-
}
在WMS服务端构造了一个Session实例对象。
AttachInfo构造过程
frameworks\base\core\java\android\view\ View.java
-
AttachInfo(IWindowSession session, IWindow window,
-
ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer) {
-
mSession = session;//IWindowSession代理对象,用于与WMS通信
-
mWindow = window;//W对象
-
mWindowToken = window.asBinder();//W本地Binder对象
-
mViewRootImpl = viewRootImpl;//ViewRootImpl实例
-
mHandler = handler;//ViewRootHandler对象
-
mRootCallbacks = effectPlayer;//ViewRootImpl实例
-
}
创建Choreographer对象
在Android Project Butter分析中介绍了Android4.1引入VSYNC、Triple Buffer和Choreographer来改善Android先天存在的UI流畅性差问题,有关Choreographer的实现过程请参看Android系统Choreographer机制实现过程。
视图View添加过程
窗口管理器WindowManagerImpl为当前添加的窗口创建好各种对象后,调用ViewRootImpl的setView函数向WMS服务添加一个窗口对象。
-
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
-
synchronized (this) {
-
if (mView == null) {
-
//将DecorView保存到ViewRootImpl的成员变量mView中
-
mView = view;
-
mFallbackEventHandler.setView(view);
-
mWindowAttributes.copyFrom(attrs);
-
attrs = mWindowAttributes;
-
mClientWindowLayoutFlags = attrs.flags;
-
setAccessibilityFocus(null, null);
-
//DecorView实现了RootViewSurfaceTaker接口
-
if (view instanceof RootViewSurfaceTaker) {
-
mSurfaceHolderCallback =
-
((RootViewSurfaceTaker)view).willYouTakeTheSurface();
-
if (mSurfaceHolderCallback != null) {
-
mSurfaceHolder = new TakenSurfaceHolder();
-
mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
-
}
-
}
-
...
-
//同时将DecorView保存到mAttachInfo中
-
mAttachInfo.mRootView = view;
-
mAttachInfo.mScalingRequired = mTranslator != null;
-
mAttachInfo.mApplicationScale = mTranslator == null ? 1.0f : mTranslator.applicationScale;
-
if (panelParentView != null) {
-
mAttachInfo.mPanelParentWindowToken
-
= panelParentView.getApplicationWindowToken();
-
}
-
...
-
//在添加窗口前进行UI布局
-
①requestLayout();
-
if ((mWindowAttributes.inputFeatures& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
-
mInputChannel = new InputChannel();
-
}
-
try {
-
mOrigWindowType = mWindowAttributes.type;
-
mAttachInfo.mRecomputeGlobalAttributes = true;
-
collectViewAttributes();
-
//将窗口添加到WMS服务中,mWindow为W本地Binder对象,通过Binder传输到WMS服务端后,变为IWindow代理对象
-
②res = sWindowSession.add(mWindow, mSeq, mWindowAttributes,
-
getHostVisibility(), mAttachInfo.mContentInsets,
-
mInputChannel);
-
} catch (RemoteException e) {
-
...
-
}
-
...
-
//建立窗口消息通道
-
if (view instanceof RootViewSurfaceTaker) {
-
mInputQueueCallback =
-
((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
-
}
-
if (mInputChannel != null) {
-
if (mInputQueueCallback != null) {
-
mInputQueue = new InputQueue(mInputChannel);
-
mInputQueueCallback.onInputQueueCreated(mInputQueue);
-
} else {
-
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,Looper.myLooper());
-
}
-
}
-
...
-
}
-
}
-
}
通过前面的分析可以知道,用户自定义的UI作为一个子View被添加到DecorView中,然后将顶级视图DecorView添加到应用程序进程的窗口管理器中,窗口管理器首先为当前添加的View创建一个ViewRootImpl对象、一个布局参数对象ViewGroup.LayoutParams,然后将这三个对象分别保存到当前应用程序进程的窗口管理器WindowManagerImpl中,最后通过ViewRootImpl对象将当前视图对象注册到WMS服务中。
ViewRootImpl的setView函数向WMS服务添加一个窗口对象过程:
1) requestLayout()在应用程序进程中进行窗口UI布局;
2) WindowSession.add()向WMS服务注册一个窗口对象;
3) 注册应用程序进程端的消息接收通道;
窗口UI布局过程
frameworks\base\core\java\android\view\ViewRootImpl.java
-
public void requestLayout() {
-
//检查当前线程是否是UI线程
-
checkThread();
-
//标识当前正在请求UI布局
-
mLayoutRequested = true;
-
scheduleTraversals();
-
}
窗口布局过程必须在UI线程中进行,因此该函数首先检查调用requestLayout()函数的线程是否为创建ViewRootImpl对象的线程。然后调用scheduleTraversals()函数启动Choreographer的Callback遍历过程。
-
void scheduleTraversals() {
-
if (!mTraversalScheduled) {
-
mTraversalScheduled = true;
-
//暂停UI线程消息队列对同步消息的处理
-
mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
-
//向Choreographer注册一个类型为CALLBACK_TRAVERSAL的回调,用于处理UI绘制
-
mChoreographer.postCallback(
-
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
-
//向Choreographer注册一个类型为CALLBACK_INPUT的回调,用于处理输入事件
-
scheduleConsumeBatchedInput();
-
}
-
}
关于Choreographer的postCallback()用法在前面进行了详细的介绍,当Vsync事件到来时,mTraversalRunnable对象的run()函数将被调用。
frameworks\base\core\java\android\view\ViewRootImpl.java
-
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
-
final class TraversalRunnable implements Runnable {
-
@Override
-
public void run() {
-
doTraversal();
-
}
-
}
mTraversalRunnable对象的类型为TraversalRunnable,该类实现了Runnable接口,在其run()函数中调用了doTraversal()函数来完成窗口布局。
-
void doTraversal() {
-
if (mTraversalScheduled) {
-
mTraversalScheduled = false;
-
mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
-
if (mProfile) {
-
Debug.startMethodTracing("ViewAncestor");
-
}
-
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");
-
try {
-
performTraversals();
-
} finally {
-
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
-
}
-
if (mProfile) {
-
Debug.stopMethodTracing();
-
mProfile = false;
-
}
-
}
-
}
performTraversals函数相当复杂,其主要实现以下几个重要步骤:
1.执行窗口测量;
2.执行窗口注册;
3.执行窗口布局;
4.执行窗口绘图;
-
private void performTraversals() {
-
// cache mView since it is used so much below...
-
final View host = mView;
-
if (host == null || !mAdded)
-
return;
-
mWillDrawSoon = true;
-
boolean windowSizeMayChange = false;
-
boolean newSurface = false;
-
boolean surfaceChanged = false;
-
WindowManager.LayoutParams lp = mWindowAttributes;
-
int desiredWindowWidth;
-
int desiredWindowHeight;
-
final View.AttachInfo attachInfo = mAttachInfo;
-
final int viewVisibility = getHostVisibility();
-
boolean viewVisibilityChanged = mViewVisibility != viewVisibility
-
|| mNewSurfaceNeeded;
-
WindowManager.LayoutParams params = null;
-
if (mWindowAttributesChanged) {
-
mWindowAttributesChanged = false;
-
surfaceChanged = true;
-
params = lp;
-
}
-
...
-
/****************执行窗口测量******************/
-
boolean layoutRequested = mLayoutRequested && !mStopped;
-
if (layoutRequested) {
-
...
-
// Ask host how big it wants to be
-
windowSizeMayChange |= measureHierarchy(host, lp, res,
-
desiredWindowWidth, desiredWindowHeight);
-
}
-
...
-
/****************向WMS服务添加窗口******************/
-
if (mFirst || windowShouldResize || insetsChanged ||
-