Diretório de artigos
prefácio
Esta série analisa principalmente o processo relacionado ao desenho de View, não se limitando aos View
métodos de onMeasure()
, , e também inclui a onLayout()
análise de classes relacionadas de ,onDraw()
ViewRootImpl
VSync
Choreographer
一.ActivityThread
Se você precisa descobrir o processo, onMeasure()
você precisa analisar ViewRootImpl primeiro, que é criado em .onLayout()
onDraw()
ViewRootImpl
handleResumeActivity
1.1 O método handleResumeActivity
O método handleResumeActivity é um método no ActivityThread, que será chamado após o início da Activity.
@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
unscheduleGcIdler();
mSomeActivitiesChanged = true;
// 调用performResumeActivity,最后会调用Activity的onResume方法
// 这里蕴含一个知识点,在onResume中无法获取View的宽高
// 原因是onMeasure之类的方法是在ViewRootImpl里面执行的,ViewRootImpl却是在onResume调用后创建的!
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
if (r == null) {
return;
}
if (mActivitiesToBeDestroyed.containsKey(token)) {
return;
}
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) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
// 这里面创建了ViewRootImpl
// decor是DecorView,是View树结构的根View
wm.addView(decor, l);
} else {
a.onWindowAttributesChanged(l);
}
}
} else if (!willBeVisible) {
if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true;
}
//...省略部分代码
}
ViewRootImpl
Criado por dentro wm.addView(decor, l);
. Em seguida, você precisa inserir WindowManager
o código para aprender.
1.2 WindowManager
Os diagramas de relacionamento de , , e ViewManager
são WindowManager
dados WindowManagerImpl
abaixo . , essas são interfaces, que podem ser consideradas como classes proxy, que são as classes que realmente fazem as coisas. Pela figura acima, podemos saber que é como o intermediário entre e , e é criado por meio de . código mostra como abaixo:WindowManagerGlobal
ViewRootImpl
ViewManager
WindowManager
WindowManagerImpl
WindowManagerGlobal
ViewRootImpl
WindowManager
View
ViewRootImpl
WindowManagerGlobal
// WindowManagerGlobal类
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow, int userId) {
//...省略部分代码
// 创建ViewRootImpl
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
try {
// 关键点,调用ViewRootImpl的setView函数
root.setView(view, wparams, panelParentView, userId);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
//...省略部分代码
}
Dois. ViewRootImpl
Depois de criar ViewRootImpl
, continue chamando setView
o método:
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, int userId) {
synchronized (this) {
//...省略部分代码
mSoftInputMode = attrs.softInputMode;
mWindowAttributesChanged = true;
mAttachInfo.mRootView = view;
mAttachInfo.mScalingRequired = mTranslator != null;
mAttachInfo.mApplicationScale =
mTranslator == null ? 1.0f : mTranslator.applicationScale;
if (panelParentView != null) {
mAttachInfo.mPanelParentWindowToken
= panelParentView.getApplicationWindowToken();
}
mAdded = true;
int res;
// 在这个方法中执行绘制流程以及调整时序和接受Vsync信号
requestLayout();
InputChannel inputChannel = null;
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
inputChannel = new InputChannel();
}
mForceDecorViewVisibility = (mWindowAttributes.privateFlags
& PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
//...省略部分代码
}
}
2.1 método requestLayout
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
// 检测线程,看看是不是主线程
checkThread();
mLayoutRequested = true;
// 和Choreographer相关的
scheduleTraversals();
}
}
scheduleTraversals
É um método muito importante, Choreographer
métodos relacionados para execução.
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
O mais importante aqui é Choreographer
esta classe, que aceita principalmente o sinal VSync e seu processamento lógico relacionado.O próximo capítulo fará uma análise aproximada desta classe.
Resumir
Através da análise acima, sabemos que ViewRootImpl é criado após onResume ser chamado, e então executar o DecorView
método , , então não podemos obter a largura e altura da View em onResume , pois a View ainda não foi medida.onMeasure()
onLayout()
onDraw()