Annuaire d'articles
avant-propos
Cette série analyse principalement le processus lié au dessin de View, non limité aux méthodes View
de , , et comprend également l'analyse des classes associées de ,onMeasure()
onLayout()
onDraw()
ViewRootImpl
VSync
Choreographer
一.ActivityThread
Si vous avez besoin de comprendre le processus, onMeasure()
vous devez d'abord analyser ViewRootImpl, qui est créé dans .onLayout()
onDraw()
ViewRootImpl
handleResumeActivity
1.1 La méthode handleResumeActivity
La méthode handleResumeActivity est une méthode dans ActivityThread, qui sera appelée après le démarrage de l'activité.
@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
Créé à l'intérieur wm.addView(decor, l);
. Ensuite, vous devez entrer WindowManager
le code pour apprendre.
1.2 Gestionnaire de fenêtres
Le diagramme de relation de ViewManager
, WindowManager
, WindowManagerImpl
, WindowManagerGlobal
et est donné ci-dessous . , ce sont des interfaces, qui peuvent être considérées comme des classes proxy, qui sont les classes qui font réellement des choses. D'après la figure ci-dessus, nous pouvons savoir qu'il est comme l'intermédiaire entre et , et qu'il est créé par . code afficher comme ci-dessous: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;
}
//...省略部分代码
}
Deux. ViewRootImpl
Après avoir créé ViewRootImpl
, continuez à appeler setView
la méthode :
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éthode requestLayout
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
// 检测线程,看看是不是主线程
checkThread();
mLayoutRequested = true;
// 和Choreographer相关的
scheduleTraversals();
}
}
scheduleTraversals
Est une méthode très importante, Choreographer
des méthodes connexes pour l'exécution.
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
La chose la plus importante ici est Choreographer
cette classe, qui accepte principalement le signal VSync et son traitement logique associé.Le chapitre suivant fera une analyse grossière de cette classe.
Résumer
Grâce à l'analyse ci-dessus, nous savons que ViewRootImpl est créé après l'appel de onResume, puis exécute la DecorView
méthode , , de sorte que nous ne pouvons pas obtenir la largeur et la hauteur de la vue dans onResume , car la vue n'a pas encore été mesurée.onMeasure()
onLayout()
onDraw()