View的绘制过程
文章目录
上次我们分析了Activity的启动过程,我们已经分析到ActivityThread.main函数,接下来两篇文章我们分析Activity的绘制、时间分发过程。以前,Activity的绘制在我的印象中就measure、lyaout、draw三个过程,对于这三个过程具体的调用过程和细节知之甚少,下面我们就来分析一下Activity的绘制过程。
- Step1 – ActivityThread.main()
//android.app.ActivityThread.java
public static final void main(String[] args) {
...
//初始化主线程消息循环
Looper.prepareMainLooper();
//由于ApplicationThread是ActivityThread的成员变量,所以同时也new ApplicationThread
ActivityThread thread = new ActivityThread();
//step2
thread.attach(false);
Looper.loop();
...
thread.detach();
...
}
}
- Step2 – attach(false)
//android.app.ActivityThread.java
private final void attach(boolean system) {
sThreadLocal.set(this);
mSystemThread = system;
//非系统应用
if (!system) {
ViewRoot.addFirstDrawHandler(new Runnable() {
public void run() {
ensureJitEnabled();//确保开启JNI
}
});
...
RuntimeInit.setApplicationObject(mAppThread.asBinder());
IActivityManager mgr = ActivityManagerNative.getDefault();//获取ActivityManagerService的Binder代理
try {
//Step3
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
}
}
//系统应用
...
//添加OnLowMemory等事件回调
ViewRoot.addConfigCallback(...);
- Step3 – attachApplication(mAppThread)
//com.android.server.am.ActivityManagerService.java
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();//获取调用进程PID
final long origId = Binder.clearCallingIdentity();
//Step4
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
- Step4 – attachApplicationLocked()
//com.android.server.am.ActivityManagerService.java
private final boolean attachApplicationLocked(IApplicationThread thread,int pid) {
// Find the application record that is being attached... either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads.
ProcessRecord app;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
}
...
// 初始化ProcessRecord,这个变量是存储在AMS中的
app.thread = thread;
app.curAdj = app.setAdj = -100;
app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.forcingToForeground = null;
app.foregroundServices = false;
app.debugging = false;
...
//命令客户进程运行指定的Activity所在的APK文件,这个函数最终会调用ActivityThread.handleBindApplication
//Step5
thread.bindApplication(...)
...
//Step6
if (realStartActivityLocked(hr, app, true, true)) {
didSomething = true;
}
// Find any services that should be running in this process...
...
// Check if the next broadcast receiver is in this process...
...
// Check whether the next backup agent is in this process...
...
- Step5 – handleBindApplication(AppBindData)
//android.os.ActivityThread.java
private final void handleBindApplication(AppBindData data) {
...
// 新建Application,Step5.1
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
- Step5.1 – makeApplication(boolean forceDefaultAppClass,Instrumentation instrumentation)
//android.os.ActivityThread.java
public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) {
if (mApplication != null) {
return mApplication;
}
Application app = null;
String appClass = mApplicationInfo.className;
try {
java.lang.ClassLoader cl = getClassLoader();
ContextImpl appContext = new ContextImpl();
appContext.init(this, null, mActivityThread);
//创建Application对象,并将appContext attach到Application对象上
app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
appContext.setOuterContext(app);
}
mActivityThread.mAllApplications.add(app);
mApplication = app;
return app;
}
- Step6 – realStartActivityLocked()
//com.android.server.am.ActivityManagerService.java
private final boolean realStartActivityLocked(HistoryRecord r,ProcessRecord app, boolean andResume, boolean checkConfig)
throws RemoteException {
...
r.app = app;
...
//Step7
app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
System.identityHashCode(r),
r.info, r.icicle, results, newIntents, !andResume,
isNextTransitionForward());
...
- Step7 – scheduleLaunchActivity
通过消息循环最终会调用handleLaunchActivity
//android.os.ActivityThread.java
private final void handleLaunchActivity(ActivityRecord r, Intent customIntent) {
...
//Step8
Activity a = performLaunchActivity(r, customIntent);
...
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
//Step9
handleResumeActivity(r.token, false, r.isForward);
}
...
}
- Step8 – performLaunchActivity
private final Activity performLaunchActivity(ActivityRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
...
//设置启动Activity信息
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);
}
Activity activity = null;
...
//通过反射生成Activity
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
r.intent.setExtrasClassLoader(cl);
...
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (activity != null) {
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(mConfiguration);
//Step8.1
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstance,
r.lastNonConfigurationChildInstances, config);
//调用Activity.OnCreate函数
mInstrumentation.callActivityOnCreate(activity, r.state);
if (!r.activity.mFinished) {
//调用Activity.OnStart函数
activity.performStart();
r.stopped = false;
}
return activity;
}
- Step8.1 – attach
//android.app.Activity.java
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,
Object lastNonConfigurationInstance,
HashMap<String,Object> lastNonConfigurationChildInstances,
Configuration config) {
//将Context attach到activity
attachBaseContext(context);
//新建PhoneWindow对象
mWindow = new PhoneWindow(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
...
//设置UI线程
mUiThread = Thread.currentThread();
//设置Activity相关属性
mMainThread = aThread;
mInstrumentation = instr;
mToken = token;
mIdent = ident;
mApplication = application;
mIntent = intent;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstance = lastNonConfigurationInstance;
mLastNonConfigurationChildInstances = lastNonConfigurationChildInstances;
...
}
- Step9 – handleResumeActivity
//android.os.ActivityThread.java
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
//这里会调用performRestart,通过状态来判断是否回调Activity.OnRestart()
ActivityRecord r = performResumeActivity(token, clearHide);
if (r != null) {
final Activity a = r.activity;
...
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;
//Step10
wm.addView(decor, l);
}
...
}
- Step10 – WindowManagerGlobal.addView
WindowManagerImpl.addView最终调用WindowManagerGlobal.addView
//android.view.WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...
ViewRootImpl root;
获取ViewRootImpl
...
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
// do this last because it fires off messages to start doing things
root.setView(view, wparams, panelParentView);
}
- Step11 – ViewRootImpl .setView
//android.view.ViewRootImpl .java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
...
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
//Step12
requestLayout();
...
}
- Step12 – requestLayout
//android.view.ViewRootImpl .java
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
//检查当前线程是否是UI线程
checkThread();
mLayoutRequested = true;
//Step 13
scheduleTraversals();
}
}
- Step13 – ViewRootImpl.scheduleTraversals
void scheduleTraversals() {
if (!mTraversalScheduled) {
...
//这里通过Runable调用ViewRootImpl.doTraversal Step14
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
...
}
- Step14 – ViewRootImpl.doTraversal
void doTraversal() {
if (mTraversalScheduled) {
//Step15
performTraversals();
}
- Step15 – ViewRootImpl.performTraversals
private void performTraversals() {
...
// Ask host how big it wants to be
//开始measure过程
windowSizeMayChange |= measureHierarchy(host, lp, res,desiredWindowWidth, desiredWindowHeight);
...
if (didLayout) {
//开始Layout过程
performLayout(lp, desiredWindowWidth, desiredWindowHeight);
}
...
//开始Draw过程
//Step16
performDraw();
...
}
- Step16 – ViewRootImpl.drawSoftware
performDraw会调用ViewRootImpl.draw然后会调用ViewRootImpl.drawSoftware。
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
boolean scalingRequired, Rect dirty) {
// Draw with software renderer.
...
final Canvas canvas;
try {
canvas.translate(-xoff, -yoff);
if (mTranslator != null) {
mTranslator.translateCanvas(canvas);
}
canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
attachInfo.mSetIgnoreDirtyState = false;
//进入Draw过程
mView.draw(canvas);
drawAccessibilityFocusedDrawableIfNeeded(canvas);
} finally {
if (!attachInfo.mSetIgnoreDirtyState) {
// Only clear the flag if it was not set during the mView.draw() call
attachInfo.mIgnoreDirtyState = false;
}
}
....
return true;
}