当前位置:网站首页>Drawing mechanism of view (II)
Drawing mechanism of view (II)
2022-07-02 07:27:00 【android_ Mr_ summer】
brief introduction
The last article described rendering android Source code analysis of layout view The drawing mechanism of ( One ), Analyzed in Activity in onCreate() Method execution setContentView() Internal implementation mechanism , as well as LayoutInflate Object for layout pull, To be added to the parent layout . So much bedding has been done , We also need for view The drawing of officially enters the analysis .
Catalog
- ViewRootImpl Process analysis
- analysis onMeasure()
ViewRootImpl Process analysis
Through the analysis of the previous article, we know Activity The top of View yes DecorView, What we do is to add components to its sub layout , This led us to think ,DecorView How to render pages ?
When Activity initialization Window And add layouts to PhoneWindow The inner class of DecorView After the class ,ActivityThread Class will call handleResumeActivity Method to set the top-level view DecorView Add to PhoneWindow window , Let's see handlerResumeActivity Method implementation
final void handleResumeActivity(IBinder token,boolean clearHide, boolean isForward, boolean reallyResume) {
...
if (r.window == null && !a.mFinished && willBeVisible) {
// Get the current Activity Of PhoneWindow object
r.window = r.activity.getWindow();
// Get the current phoneWindow Inner class DecorView object
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
// Appropriate current Activity Of WindowManagerImpl object
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) {
// Tag root layout DecorView Has been added to the window
a.mWindowAdded = true;
// Layout the root DecorView Add to current Activity On the window of
wm.addView(decor, l);
...
The above process is to PhoneWindow Inner class in DecorView adopt ViewManager Add to Activity In the window of , We mainly look at wm.addView(decor, l) Method , see WindowManager Implementation class of WindowManagerImpl Source code :
@Override
public void addView(View view, ViewGroup.LayoutParams params) {
// The object is WindowManagerGlobal object
mGlobal.addView(view, params, mDisplay, mParentWindow);
}
The code above is simple , Directly internal call WindowManagerGlobar Of addView Methods :
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...
ViewRootImpl root;
View panelParentView = null;
...
// Instantiation ViewRootImpl object
root = new ViewRootImpl(view.getContext(), display);
...
// do this last because it fires off messages to start doing things
try {
// Pass in the parameters DecorView Set to root in
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
...
}
}
First of all, we are right ViewRootImpl Object to instantiate , And then call setView Method , take DecorView Pass in , Let's continue to check ViewRootImpl The source code :
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
// Put the top-level view DecorView Assigned to global mView
mView = view;
...
// Tag added DecorView
mAdded = true;
...
// Request layout
requestLayout();
...
}
}
The implementation of this method is a little long , Look directly at the above lines of code :, First of all, will DecorView Copy to global mView, Then passed requestLayout() Request layout :
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
// Execute thread
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
}
}
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
try {
performTraversals();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
}
The above code is mainly
1. stay scheduleTraversals Will call Choregrapher.postCallback, Take it post get out , and postSyncBarrier Method disables subsequent message processing , once post Out of sync Barrier after , All messages that are not called asynchronously will be stopped from being distributed .
2.mHandler.getLooper().removeSyncBarrier(mTraversalBarrier), Call again performTraversals function . Delete a synchronized Barrier. In the source code , Is to delete one with Message.arg1 by mTraversalBarrier Of Message. in other words , Will start with MessageQueue Zhongba mTraversalBarrier This Message Delete , And then call performTraversals().
private void performTraversals() {
..
// get view Measurement specification of width and height ,mWidth and mHeight Represents the width and height of the window ,lp.widthhe and lp.height Express DecorView Root layout width and height
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
// Ask host how big it wants to be
// Perform the measurement operation
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
...
// Perform layout operations
performLayout(lp, desiredWindowWidth, desiredWindowHeight);
...
// Perform drawing operations
performDraw();
}
private int getRootMeasureSpec(int windowSize, int rootDimension) {
int measureSpec;
switch (rootDimension) {
case ViewGroup.LayoutParams.MATCH_PARENT:
measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
break;
case ViewGroup.LayoutParams.WRAP_CONTENT:
measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
break;
default:
measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
break;
}
return measureSpec;
}
The main process of this method reflects View The three main steps of rendering , They are measurement , Layout , Draw three stages .
analysis onMeasure()
onMeasure() Method to measure the size of the view ,View The drawing process of the system will start from ViewRoot Of performTraversals() Method , Called inside View Of measure() Method .measure() Method accepts two parameters ,widthMeasureSpec and heightMeasureSpec, These two values are used to determine the specification and size of the width and height of the view, respectively .
First look at it. onMeasure() Method (View.java):
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
boolean optical = isLayoutModeOptical(this);
if (optical != isLayoutModeOptical(mParent)) {
Insets insets = getOpticalInsets();
int opticalWidth = insets.left + insets.right;
int opticalHeight = insets.top + insets.bottom;
measuredWidth += optical ? opticalWidth : -opticalWidth;
measuredHeight += optical ? opticalHeight : -opticalHeight;
}
setMeasuredDimensionRaw(measuredWidth, measuredHeight);
}
stay onMeasure() Call in method setMeasuredDimension() Method , about view Carry out the measurement operation . First look at it. getDefaultSize() What does the method deal with :
public static int getDefaultSize(int size, int measureSpec) {
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
result = size;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}
Through the above code, we can understand : adopt MeasureSpec Get two integer values , One is the measurement mode , The other is to measure the size . see MeasureSpec Source code :
public static class MeasureSpec {
private static final int MODE_SHIFT = 30;
private static final int MODE_MASK = 0x3 << MODE_SHIFT;
/** * Measure specification mode: The parent has not imposed any constraint * on the child. It can be whatever size it wants. */
public static final int UNSPECIFIED = 0 << MODE_SHIFT;
/** * Measure specification mode: The parent has determined an exact size * for the child. The child is going to be given those bounds regardless * of how big it wants to be. */
public static final int EXACTLY = 1 << MODE_SHIFT;
/** * Measure specification mode: The child can be as large as it wants up * to the specified size. */
public static final int AT_MOST = 2 << MODE_SHIFT;
/** * Creates a measure specification based on the supplied size and mode. * * The mode must always be one of the following: * <ul> * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> * </ul> * * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's * implementation was such that the order of arguments did not matter * and overflow in either value could impact the resulting MeasureSpec. * {@link android.widget.RelativeLayout} was affected by this bug. * Apps targeting API levels greater than 17 will get the fixed, more strict * behavior.</p> * * @param size the size of the measure specification * @param mode the mode of the measure specification * @return the measure specification based on size and mode */
public static int makeMeasureSpec(int size, int mode) {
if (sUseBrokenMakeMeasureSpec) {
return size + mode;
} else {
return (size & ~MODE_MASK) | (mode & MODE_MASK);
}
}
/** * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED * will automatically get a size of 0. Older apps expect this. * * @hide internal use only for compatibility with system widgets and older apps */
public static int makeSafeMeasureSpec(int size, int mode) {
if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) {
return 0;
}
return makeMeasureSpec(size, mode);
}
/** * Extracts the mode from the supplied measure specification. * * @param measureSpec the measure specification to extract the mode from * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, * {@link android.view.View.MeasureSpec#AT_MOST} or * {@link android.view.View.MeasureSpec#EXACTLY} */
public static int getMode(int measureSpec) {
return (measureSpec & MODE_MASK);
}
/** * Extracts the size from the supplied measure specification. * * @param measureSpec the measure specification to extract the size from * @return the size in pixels defined in the supplied measure specification */
public static int getSize(int measureSpec) {
return (measureSpec & ~MODE_MASK);
}
...
}
MeasureSpec Representing one 32 position int value , high 2 On behalf of SpecMode, low 30 On behalf of SpecSize,SpecMode Measurement mode , and specSize It refers to the specification size in a certain measurement mode .
1. EXACTLY
Indicates that the parent view expects the size of the child view to be determined by specSize It depends on the value of , The system will set the size of the sub view according to this rule by default , You can also set it to any size according to your own wishes .
2. AT_MOST
Indicates that the subview can only be at most specSize The size specified in , This view should be set as small as possible , And promise not to exceed specSize. The system will set the size of the sub view according to this rule by default , You can also set it to any size according to your own wishes .
3. UNSPECIFIED
It means that developers can set the view to any size according to their own wishes , No restrictions .
summary :
1. commonly view We don't need to rewrite onMeasure() Method , We can follow directly view Just go through the testing process , Of course view Inherit view When , Can be rewritten onMeasure() Methods to customize .
for example :
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(300,300);
}
In this case View The default measurement process overrides , Whether defined in the layout file MyView What is the size of this view , The final size displayed on the interface will be 300*300.
2. If we need to deal with wrap-content If so, we can onMeasure() Rewriting of , Because through the above source code, we know ,specSize specifications AT_MOST and EXACTLY They are all the same size according to the parent layout , So we have to re onMeasure() Come on specSize() specifications AT_MOST This value is used to set the specified value .
It should be noted that , stay setMeasuredDimension() After method call , We can use getMeasuredWidth() and getMeasuredHeight() To get the width and height measured by the view , Before that, the value obtained by calling these two methods will be 0.
That's about onMeasure() Analysis of . Let's continue to analyze onLayout() and onDraw()view The drawing mechanism of ( 3、 ... and )
边栏推荐
- A summary of a middle-aged programmer's study of modern Chinese history
- Only the background of famous universities and factories can programmers have a way out? Netizen: two, big factory background is OK
- 华为机试题-20190417
- Oracle general ledger balance table GL for foreign currency bookkeeping_ Balance change (Part 1)
- 【论文介绍】R-Drop: Regularized Dropout for Neural Networks
- Oracle rman自动恢复脚本(生产数据向测试迁移)
- Oracle RMAN automatic recovery script (migration of production data to test)
- 叮咚,Redis OM对象映射框架来了
- Sparksql data skew
- Alpha Beta Pruning in Adversarial Search
猜你喜欢
外币记账及重估总账余额表变化(下)
【信息检索导论】第七章搜索系统中的评分计算
一份Slide两张表格带你快速了解目标检测
读《敏捷整洁之道:回归本源》后感
MySQL has no collation factor of order by
SSM二手交易网站
【BERT,GPT+KG调研】Pretrain model融合knowledge的论文集锦
Pratique et réflexion sur l'entrepôt de données hors ligne et le développement Bi
Alpha Beta Pruning in Adversarial Search
[introduction to information retrieval] Chapter 3 fault tolerant retrieval
随机推荐
@Transitional step pit
pySpark构建临时表报错
Oracle EBS interface development - quick generation of JSON format data
DNS攻击详解
PHP uses the method of collecting to insert a value into the specified position in the array
[medical] participants to medical ontologies: Content Selection for Clinical Abstract Summarization
Error in running test pyspark in idea2020
Classloader and parental delegation mechanism
One field in thinkphp5 corresponds to multiple fuzzy queries
MySQL组合索引加不加ID
Oracle EBS ADI development steps
读《敏捷整洁之道:回归本源》后感
Practice and thinking of offline data warehouse and Bi development
Proteus -- RS-232 dual computer communication
MySQL无order by的排序规则因素
Oracle EBS database monitoring -zabbix+zabbix-agent2+orabbix
优化方法:常用数学符号的含义
类加载器及双亲委派机制
Yolov5 practice: teach object detection by hand
SSM student achievement information management system