在Android应用程序的四大组件中,只有Activity组件与UI相关,它描述的是应用程序窗口,因此我们通过它的UI实现来分析Android系统在Java层的UI实现。
首先,我们得从Activity的启动开始:
再我们调用startActivity
后,最终会调用startActivityForResult()
方法,然后在这个方法里面最终会调用
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, who,
intent, requestCode, options);
在上面方法中,最终会调用
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target, requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
其中ActivityManager.getService()
得到的IActivityManager,看到I开头的,应该可以想到这个是一个接口,而且还是一个aidl接口,它的实现的类是ActivityManagerService
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback
然后我们找到它的startActivity
方法:
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
}
@Override
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
enforceNotIsolatedCaller("startActivity");
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, "startActivity", null);
// TODO: Switch to user app stacks here.
return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
profilerInfo, null, null, bOptions, false, userId, null, null,
"startActivityAsUser");
}
我们可以看到,最后是调用了mActivityStarter.startActivityMayWait
方法,这个ActivityStarter是什么呢?
官方介绍:
Controller for interpreting how and then launching activities.
一个Controller,用于解释如何然后启动Activity
然后我们找到startActivityMayWait
方法,在该方法中会调用startActivityLocked
方法,经过一系列的骚操作,最终会调用app.thread.scheduleLaunchActivity
方法。
app.thread得到的是IApplication,它的实现类是ApplicationThread
private class ApplicationThread extends IApplicationThread.Stub
ApplicationThread的实现在ActivityThread中,然后再经过一系列调用后,消息传递,最终会调用handleLaunchActivity
方法,在这个方法中调用performLaunchActivity
方法,得到了一个Activity。
然后我们重点看看performLaunchActivity
方法:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//得到Activity组件信息
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}
if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}
//得到Context,ContextImpl 是Contenx的具体实现
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
//使用类加载器创建Activity对象
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
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);
}
}
try {
//尝试创建Application对象
//一个App中只有一个Application对象
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
if (localLOGV) Slog.v(
TAG, r + ": app=" + app
+ ", appName=" + app.getPackageName()
+ ", pkg=" + r.packageInfo.getPackageName()
+ ", comp=" + r.intent.getComponent().toShortString()
+ ", dir=" + r.packageInfo.getAppDir());
if (activity != null) {
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (r.overrideConfig != null) {
config.updateFrom(r.overrideConfig);
}
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
Window window = null;
if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
window = r.mPendingRemoveWindow;
r.mPendingRemoveWindow = null;
r.mPendingRemoveWindowManager = null;
}
appContext.setOuterContext(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, window, r.configCallback);
if (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
checkAndBlockForNetworkAccess();
activity.mStartedActivity = false;
//设置主题
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
activity.mCalled = false;
//调用Activity.onCreate方法
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onCreate()");
}
r.activity = activity;
}
r.setState(ON_CREATE);
mActivities.put(r.token, r);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to start activity " + component
+ ": " + e.toString(), e);
}
}
return activity;
}
我们知道,调用了onCreate方法后,我们自己写的布局就加载进去了。
在上面的方法中,主要先创建了Context,然后创建Activity,然后是进行数据初始化,并创建Window且建立关联,然后调用Activity的onCreate方法。
Activity组件的UI实现需要与 WinodwManagerService服务和SurfaceFlinger服务进行交互,Activity组件在启动完成后,会通过一个类型为Session的Binder对象来请求WindowManagerService为它创建一个类型为WindowState的对象,用来描述它的窗口状态。Android应用程序会通过一个类型为Client的Binder对象来请求SurfaceFlinger服务为它创建一个类型为Layer的对象,用来描述它的窗口数据。
SurfaceFlinger服务为Android应用程序创建一个类型为Layer的对象之后,会返回一个类型为SurfaceLayer的Binder对象给Android应用程序,这样Android应用程序就可以通过这个Binder对象来请求SurfaceFlinger服务来分配图形缓冲区。
实时上,用来关联Activity组件和Layer对象的SurfaceLayer对象并不是由Android应用程序请求SurfaceFlinger服务来创建的,而是由WindowManagerService服务请求SurfaceFlinger服务来创建的。WindowManagerService服务得到这个SurfaceLayer对象之后,再将它的一个代理对象返回给Android应用程序这一侧的Android组件。这样,Activity组件和WindowManagerService服务就可以通过同一个SurfaceLayer对象来操作在SurfaceFlinger服务这一侧的Layer对象,而操作Layer对象的目的就是为了修改Activity组件的UI。
接下来,就根据上面代码的顺序,来看看UI是怎么渲染的:
Android应用程序在运行的过程中 ,需要访问一些特定的资源或类,这些特定的资源或者类构成了Android应用程序的运行上下文环境,Android应用程序窗口可以通过一个Context接口来访问它。
ContextImpl是Context的子类,class ContextImpl extends Context
,每个activity组件都关联有一个ContextImpl对象
我们首先看看ContextImpl和activity组件的关系:
Activity组件通过其父类ContextThemeWrapper和ContextWrapper的成员变量mBase应用了一个ContextImpl对象,这样,Activity组件以后就可以通过这个ContextImpl对象来执行一些具体的操作,例如,启动Service组件,注册广播等。同时,ContextImpl类又通过自己的成员变量mOuterContext来引用了与它关联的一个activity组件,这样,ContextImpl类也可以将一些操作转发给Activity组件来处理。
在上面的代码中,Context的创建是通过ContextImpl appContext = createBaseContextForActivity(r);
创建的。
private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
final int displayId;
try {
displayId = ActivityManager.getService().getActivityDisplayId(r.token);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
// For debugging purposes, if the activity's package name contains the value of
// the "debug.use-second-display" system property as a substring, then show
// its content on a secondary display if there is one.
String pkgName = SystemProperties.get("debug.second-display.pkg");
if (pkgName != null && !pkgName.isEmpty()
&& r.packageInfo.mPackageName.contains(pkgName)) {
for (int id : dm.getDisplayIds()) {
if (id != Display.DEFAULT_DISPLAY) {
Display display =
dm.getCompatibleDisplay(id, appContext.getResources());
appContext = (ContextImpl) appContext.createDisplayContext(display);
break;
}
}
}
return appContext;
}
可以看到,上面代码中是通过ContextImpl.createActivityContext()
来创建的
static ContextImpl createActivityContext(ActivityThread mainThread,
LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId,
Configuration overrideConfiguration) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
String[] splitDirs = packageInfo.getSplitResDirs();
ClassLoader classLoader = packageInfo.getClassLoader();
if (packageInfo.getApplicationInfo().requestsIsolatedSplitLoading()) {
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "SplitDependencies");
try {
classLoader = packageInfo.getSplitClassLoader(activityInfo.splitName);
splitDirs = packageInfo.getSplitPaths(activityInfo.splitName);
} catch (NameNotFoundException e) {
// Nothing above us can handle a NameNotFoundException, better crash.
throw new RuntimeException(e);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
}
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName,
activityToken, null, 0, classLoader);
// Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY.
displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY;
final CompatibilityInfo compatInfo = (displayId == Display.DEFAULT_DISPLAY)
? packageInfo.getCompatibilityInfo()
: CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
final ResourcesManager resourcesManager = ResourcesManager.getInstance();
// Create the base resources for which all configuration contexts for this Activity
// will be rebased upon.
context.setResources(resourcesManager.createBaseActivityResources(activityToken,
packageInfo.getResDir(),
splitDirs,
packageInfo.getOverlayDirs(),
packageInfo.getApplicationInfo().sharedLibraryFiles,
displayId,
overrideConfiguration,
compatInfo,
classLoader));
context.mDisplay = resourcesManager.getAdjustedDisplay(displayId,
context.getResources());
return context;
}
在上面的代码中,调用了ContextImpl的构造方法,创建了Context。
在ContexImpl创建之后,通过mInstrumentation.newActivity()
创建一个Activity实例,Instrumentation类是用来记录应用程序与系统的交互过程的,在step2中,我们再分析newActivity
的实现。
public Activity newActivity(Class<?> clazz, Context context,
IBinder token, Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
Object lastNonConfigurationInstance) throws InstantiationException,
IllegalAccessException {
Activity activity = (Activity)clazz.newInstance();
ActivityThread aThread = null;
activity.attach(context, aThread, this, token, 0 /* ident */, application, intent,
info, title, parent, id,
(Activity.NonConfigurationInstances)lastNonConfigurationInstance,
new Configuration(), null /* referrer */, null /* voiceInteractor */,
null /* window */, null /* activityConfigCallback */);
return activity;
}
还记得上面的代码中,也会调用这个attch方法嘛,这个方法我们后面再分析。
创建好了Activity后,是调用Application app = r.packageInfo.makeApplication(false, mInstrumentation);
尝试创建一个Application,为什么说是尝试创建呢?因为一个App中只有一个Application,如果这个Activity不是第一个启动的Activity,那么这个Application早就存在了。
之后,会调用appContext.setOuterContext(activity);
对ContexImpl的mOuterContext成员变量进行的赋值,
final void setOuterContext(Context context) {
mOuterContext = context;
}
其实在ContextImpl创建的时候,我们看看它的构造方法里面:
class ContextImpl extends Context {
......
private Context mOuterContext;
......
ContextImpl() {
// For debug only
//++sInstanceCount;
.....
mOuterContext = this;
.....
}
......
}
当一个ContextImpl对象是用来描述Activity组件的运行上下文环境的时候,那么它的成员变量mOuterContext就是指向该Activity组件。由于一个ContextImpl对象在创建的时候,并没有参数用来指明它是用来描述一个Activity组件的运行上下文的,因此,这里就暂时将它的成员变量mOuterContext指向自己。
然后调用activity.attach()
方法,进行初始化,
还记得上面吗?在创建Activity的newActivity方法中,也调用了这个方法,那么我们就看看这个方法:
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,
Window window, ActivityConfigCallback activityConfigCallback) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
//建立Window对象
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(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);
}
mUiThread = Thread.currentThread();
mMainThread = aThread;
mInstrumentation = instr;
mToken = token;
mIdent = ident;
mApplication = application;
mIntent = intent;
mReferrer = referrer;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstances = lastNonConfigurationInstances;
if (voiceInteractor != null) {
if (lastNonConfigurationInstances != null) {
mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
} else {
mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
Looper.myLooper());
}
}
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());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
mWindow.setColorMode(info.colorMode);
}
首先调用从父类ContextThemeWrapper继承下来的成员函数attachBaseContext
来设置运行上下文,即将ContextImpl对象保存在内部
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
//在Context中,下面这个方法是空实现
newBase.setAutofillClient(this);
}
//ContextThemeWrapper.java
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
}
//ContextWrapper.java
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
继续看attch方法中的代码,接下来,调用PhoneWindow的构造方法,创建了一个Winodw对象:mWindow = new PhoneWindow(this, window, activityConfigCallback);
这个PhoneWindow是用来描述当前正在启动的应用程序窗口的。这个应用程序窗口在运行的过程中,会接收到一些事件,例如:键盘,触摸屏等,这些事件需要转发给与它关联的Activity组件处理,这个转发操作是通过Window.Callback接口来实现的。Activity实现了这个接口,所以可以直接设置:
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
接下来attach方法中改的代码:
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
info指向的是一个ActivityInfo对象,用来描述当前正在启动的Activity组件的信息。其中,这个ActivityInof对象中的成员变量softInputMode
用来描述当前正在启动的Activity是否接受软键盘输入,如果接受的话,它的值就不等于WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED
并且描述的是当前正在启动的Activity组件所接受的软键盘输入模式。
在Android系统中,每一个应用程序窗口都需要一个窗口管理者来管理,因此,在attach方法中,
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
设置WindowManagerService。设置完了后,就从该window得到WindowManagerService,并保存在Activity中。
mWindowManager = mWindow.getWindowManager();
这样,该Activity以后就可以通过它的mWindowManager 来管理与它所关联的窗口。
现在,Activity初始化就完成了。
回到performLaunchActivity
方法中,在完成activity的初始化后,就利用mInstrumentation
调用Activity.onCreate方法:
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
在Instrumentation.java中
public void callActivityOnCreate(Activity activity, Bundle icicle) {
prePerformCreate(activity);
activity.performCreate(icicle);
postPerformCreate(activity);
}
public void callActivityOnCreate(Activity activity, Bundle icicle,
PersistableBundle persistentState) {
prePerformCreate(activity);
activity.performCreate(icicle, persistentState);
postPerformCreate(activity);
}
final void performCreate(Bundle icicle) {
restoreHasCurrentPermissionRequest(icicle);
onCreate(icicle);
mActivityTransitionState.readState(icicle);
performCreateCommon();
}
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
restoreHasCurrentPermissionRequest(icicle);
onCreate(icicle, persistentState);
mActivityTransitionState.readState(icicle);
performCreateCommon();
}
public void onCreate(@Nullable Bundle savedInstanceState,
@Nullable PersistableBundle persistentState) {
onCreate(savedInstanceState);
}
一般来说,我们都是听过定义一个Activity子类来实现一个Activity组件的。重写父类Activity的某些成员函数的时候,必须要回调父类Activity的这些成员函数,例如onCreate方法。这些成员函数被回调之后,Activity类会将其成员变量mCalled的值设置为true。
这样,Activity类就可以通过其成员变量mCalled来检查其子类在重写它的某些成员函数时,是否正确地回调了父类的这些成员函数。
Activity类的另外一个成员变量mVisibleFromClient用来描述一个应用程序窗口是否是可见的。如果是可见的,那么它的值就会等于true。当Activity类的成员函数onCreate被其子类回调时,它就会检查对应的应用程序窗口的主题属性android:windowNoDisplay的值是否等于true。如果等于true的话,那么就说明当前所启动的应用程序窗口是不可见的,这时候Activity类的成员变量mVisibleFromClient的值就会被设置为false,否则的话,就会被设置为true。
Activity子类在重写成员函数onCreate的时候,一般都会调用父类Activity的成员函数setContentView来为为当前正启动的应用程序窗口创建视图(View)。在接下来的文章中,我们再详细描述应用程序窗口的视图的创建过程。
现在,一个Activity组件的创建过程以及它的上下文环境的创建过程就分析完了,我们可以总结三点:
参考:
https://www.kancloud.cn/alex_wsc/androids/473770