整体绘制流程
看本篇文章时,要考虑以下几点:
- Android程序是如何启动的,Activity生命周期是如何调用的?
- 在Activity的
onCreate()方法中setContentView()是如何加载UI文件的? UI是如何绘制的?
流程分析源码基于 API 29。
Android程序流程
在刚接触Java时,了解到Java程序运行的入口是main(), 但是在日常开发App中并没有发现main()的存在,那么Android中的程序是如何开始运行的?
查阅官方资料中我们会发现在Android中有一个叫做ActivityThread的类,这个类代表的就是Android当中的主线程,在ActivityThread中可以看到有main()。
main()
public static void main(String[] args) {
//...
Looper.prepareMainLooper();
//...
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
// ...
Looper.loop();
}attach()
在main方法中可以看到ActivityThread中调用了attach()。
@UnsupportedAppUsage
private void attach(boolean system, long startSeq) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
// ...
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
// ...
}
}ActivityManager#getService()
在ActivityThread#attach()方法中可以看到通过ActivityManager#getService()方法获取了IActivityManager。
@UnsupportedAppUsage
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}@UnsupportedAppUsage
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};进入到上述代码块中, getService()通过Binder机制获取系统的ActivityManagerService服务。
ActivityManagerService#attachApplication()
在ActivityThread#attach()中调用了attachApplication()方法。
@Override
public final void attachApplication(IApplicationThread thread, long startSeq) {
synchronized (this) {
// ...
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
// ...
}
}private final boolean attachApplicationLocked(IApplicationThread thread,
int pid, int callingUid, long startSeq) {
//....
thread.bindApplication(processName, appInfo, providers,
instr2.mClass,
profilerInfo, instr2.mArguments,
instr2.mWatcher,
instr2.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new Configuration(app.getWindowProcessController().getConfiguration()),
app.compat, getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions);
//...
}attachApplication的作用实际上是将ActivityThread与ApplciationThread关联,ApllicationThread的类为activity的各种状态做了相对应的代理工作,并进行Application初始化操作。
ApplicationThread
private class ApplicationThread extends IApplicationThread.Stub {}通过上述分析,ApplicationThread当中在Activity各种生命周期中扮演了什么角色呢?
在ApplicationThread类中,系统服务通过scheduleTransaction()方法进行Activity生命周期的各种转换。(本次只是简单的从整个App运行流程上讲,Activity的启动流程后续补充。)
setContentView
在onCreate当中我们往往会使用setContentView去进行设置我们自己的布局文件或者view,那么在这当中他到底是怎么做的?通过观察源码,这个时候通过一系列线索我找到了最终的位置PhoneWindow类。
setContentView
// Activity.java
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}// Window.java
/* <p>The only existing implementation of this abstract class is
* android.view.PhoneWindow, which you should instantiate when needing a
* Window.*/
public abstract class Window {
public abstract void setContentView(@LayoutRes int layoutResID);
}// PhoneWindow.java
@Override
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene
= Scene.getSceneForLayout(mContentParent, layoutResID, getContext());
transitionTo(newScene);
} else {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
// ...
}在PhoneWindow#setCcontentView()中做了两件事(installDecor和 inflate)。
installDecor
installDecor中主要是创建了Decor(顶层视图)和contentParent视图(我们写的布局的父视图)。
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
mDecor = generateDecor(-1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
// ...
}
// ...
}generateDecor
在Window中创建顶级的view。
protected DecorView generateDecor(int featureId) {
// ...
return new DecorView(context, featureId, this, getAttributes());
}generateLayout
根据设置App的不同主题获取不同的系统父布局文件,进行布局初始化并查找id为com.android.internal.R.id.content的contentParent。
protected ViewGroup generateLayout(DecorView decor) {
// Apply data from current theme.
// 根据配置的不同主题,选择系统父布局文件
layoutResource = R.layout.screen_simple;
mDecor.startChanging();
// 加载布局文件
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
// ...
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
// ...
return contentParent;
}DecorView#onResourcesLoaded
onResourcesLoaded加载系统父布局文件,并将其添加到DecorView中。
void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
//...
final View root = inflater.inflate(layoutResource, null);
// ...
// Put it below the color views.
addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
// ...
}R.layout.screen_simple.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<ViewStub android:id="@+id/action_mode_bar_stub"
android:inflatedId="@+id/action_mode_bar"
android:layout="@layout/action_mode_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="?attr/actionBarTheme" />
<FrameLayout
android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foregroundInsidePadding="false"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>
浙公网安备 33010602011771号