深入理解View知识系列一- setContentView和LayoutInflater源码原理分析
深入理解View知识系列二- View底层工作原理以及View的绘制流程
深入理解View知识系列三-Window机制、Canvas的由来、Android事件的由来
深入理解View知识系列四-View的测量规则以及三大方法流程
我们带着问题在上一篇的基础上继续分析,View的绘制流程及工作原理,在正式分析之前我们先回顾一下上一篇的内容.
1.判断装在我们设置布局的FrameLayout是否为空,如果为空调用installDecor方法,方法中首先会先执行generateDecor()创建DecorView,接着执行generateLayout()方法设置一些Window的样式,根据样式来选择需要加载的布局,然后将布局添加到DecorView中,最后找到id为content的FrameLayout,也就是来装我们设置布局的父View。
2.通过LayoutInflater将我们设置的布局添加到id为content的FrameLayout中
3.回调Callback接口的onContentChanged()方法,这个方法在Activity中是个空实现。
1.首先会判断这个名称的构造函数是否存在,如果存在则还需要验证这个函数所属的ClassLoader是否合法,如果不合法则会置空这个构造函数并清除缓存。
2.接着继续判断构造函数是否为空,如果为空则会通过一个三元运算来加载这个名称的Class对象,这个三元运算主要是用来判断是否需要拼接要加载Class的名字。
3.然后会判断是否存在Filter过滤器,这个过滤器是用来判断是否可以创建这个Class的View对象,通过查看设置过滤器的RemoteViews和AppWeightHostView都是通过clazz.isAnnotationPresent(RemoteView.class)来判断的,如果返回为flase则执行抛出异常。
4.或者该Class的构造函数并存入HashMap中
5.在else逻辑中,主要是用来优化存在过滤器的情况,为了优化性能,系统只会在第一次的时候去验证是否允许创建这个View,并将结果存入HashMap中,下次只会取map中结果进行判断。
6.通过构造函数实例化这个View并返回
这里又提到了ActivityThread这个类,简单说一下这个类,要知道所有的程序都是需要一个入口的,Android也不例外,ActivityThread就是Android应用的入口类,Activity、Service、ContentProvider几乎都直接或者间接在这里调度。现在暂时知道这么多就好了,先不要纠结这个类,后续的会专门在四大组件系列去讲。
源码位置:/frameworks/base/core/java/android/app/ActivityThread.java
final void handleResumeActivity(IBinder token,
unscheduleGcIdler();
mSomeActivitiesChanged = true;
//ActivityClientRecord 在AMS中代表一个Activity,这个方法中会调用
//Activity的onResume方法
ActivityClientRecord r = performResumeActivity(token, clearHide);
if (r != null) {
//得到Activity
final Activity a = r.activity;
if (localLOGV) Slog.v(
TAG, "Resume " + r + " started activity: " +
a.mStartedActivity + ", hideForNow: " + r.hideForNow
+ ", finished: " + a.mFinished);
final int forwardBit = isForward ?
WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
。。。
if (r.window == null && !a.mFinished && willBeVisible) {
//获取Activity中的Window,也就是PhoneWindow
r.window = r.activity.getWindow();
//获取PhoneWindow中的DecorView
View decor = r.window.getDecorView();
//设置DecorView隐藏
decor.setVisibility(View.INVISIBLE);
//获取Activity的WindowManager
ViewManager wm = a.getWindowManager();
//获取PhoneWindow的参数
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;
//在Window中添加DecorView
wm.addView(decor, l);
}
} else if (!willBeVisible) {
if (localLOGV) Slog.v(
TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true;
}
if (!r.activity.mFinished && willBeVisible
&& r.activity.mDecor != null && !r.hideForNow) {
...
if (r.activity.mVisibleFromClient) {
//设置DecorView显示
r.activity.makeVisible();
}
}
...
} else {
try {
ActivityManagerNative.getDefault()
.finishActivity(token, Activity.RESULT_CANCELED, null, false);
} catch (RemoteException ex) {
}
}
}
首先调用执行了performResumeActivity方法,在这里方法中会调用Activity的onResume方法
获取Activity的PhoneWindow,接着拿到PhoneWindow中的DecorView并设置为隐藏,获取Activity的中WindowManger并执行addView方法将DecorView添加到Window中。
执行Activity的makeVisible方法展示DecorView,方法中就是调用了View.VISIBLE
其实在Activity的onResume方法执行了以后才开始将DecorView添加到Window中,换句话说,也就是在onResume方法中是不能直接获取View的宽度等参数的,因为这个时候连DecorView都没有添加到Window中呢,所以这时也还没有执行View的三大流程呢,又如何产生这是东西。
DecorView最终也是通过WindowManager来添加的,或者说Activity可以显示内容其实也是通过WindowManager添加View来实现的,其实Android中所有设计View展示的最终全部都是通过WindowManager的addView来添加的,例如PopupWindow、Dialog、Toast等,下一篇会详细分析
//ViewManager
public interface ViewManager
{
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}
//WIndowManager
public interface WindowManager extends ViewManager {
....
}
源码位置:/frameworks/base/core/java/android/view/WindowManagerImpl.java
public final class WindowManagerImpl implements WindowManager {
//WindowManagerGlobal是单例的
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
...
//addView
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
//跳转到WindowManagerGlobal中
mGlobal.addView(view, params, mDisplay, mParentWindow);
}
//updateView
@Override
public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
//跳转到WindowManagerGlobal中
mGlobal.updateViewLayout(view, params);
}
//removeView
@Override
public void removeView(View view) {
//跳转到WindowManagerGlobal中
mGlobal.removeView(view, false);
}
...
源码位置:/frameworks/base/core/java/android/view/WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
//1.验证参数合法性
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
if (display == null) {
throw new IllegalArgumentException("display must not be null");
}
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
//2.如果存在父Window需要调整一些参数
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else {
//设置硬件加速
final Context context = view.getContext();
if (context != null
&& (context.getApplicationInfo().flags
& ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
}
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
...
//创建ViewRootImpl
root = new ViewRootImpl(view.getContext(), display);
//设置参数属性
view.setLayoutParams(wparams);
//保存要添加view、ViewRootImpl和LayoutParams
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
}
try {
//调用了ViewRootImpl的setView
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
synchronized (mLock) {
final int index = findViewLocked(view, false);
if (index >= 0) {
removeViewLocked(index, true);
}
}
throw e;
}
}
- 检查参数的合法性
- 创建ViewRootImpl,并将要添加的view、ViewRootImpl和LayoutParams缓存起来
- 最后调用了ViewRootImpl的setView方法后逻辑跳转到ViewRootImpl中。
源码位置:/frameworks/base/core/java/android/view/ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
...
//最终在这里调用了绘制
requestLayout();
...
//通过WMS添加Window
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
...
//记住这里,下面分析View的requestLayout原理时会说
view.assignParent(this);
...
}
源码位置:/frameworks/base/core/java/android/view/ViewRootImpl.java
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
//检查线程
checkThread();
mLayoutRequested = true;
//绘制入口
scheduleTraversals();
}
}
源码位置:/frameworks/base/core/java/android/view/ViewRootImpl.java
void checkThread() {
if (mThread != Thread.currentThread()) {
//这个异常熟悉吗
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
源码位置:/frameworks/base/core/java/android/view/ViewRootImpl.java
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
//消息屏蔽,这里的知识会在以后去讲
mTraversalBarrier =
mHandler.getLooper().getQueue().postSyncBarrier();
//发送一个异步的消息,最终会执行传入的Runnable
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
源码位置:/frameworks/base/core/java/android/view/ViewRootImpl.java
//字段声明
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
//TraversalRunnable的定义
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
//run方法中的 doTraversal方法
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
//解除消息屏障
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
//真正的绘制起点
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
源码位置:/frameworks/base/core/java/android/view/ViewRootImpl.java
private void performTraversals() {
//顶层的View,或者可以理解成是DecorView
final View host = mView;
...
//通知被添加到窗口了,传入了mAttachInfo
host.dispatchAttachedToWindow(mAttachInfo, 0);
...
// 记住这个方法,一会回来看
getRunQueue().executeActions(mAttachInfo.mHandler);
...
//measure过程
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
....
//layout过程
performLayout(lp, desiredWindowWidth, desiredWindowHeight);
....
//通知layout完成了
mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();
....
//draw过程
performDraw();
}
源码位置:/frameworks/base/core/java/android/view/View.java
public boolean post(Runnable action) {
//如果mAttachInfo 不为空则使用mAttachInfo中的Handler去post
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
//否则调用ViewRootImpl.getRunQueue()去post
ViewRootImpl.getRunQueue().post(action);
return true;
}
源码位置:/frameworks/base/core/java/android/view/View.java
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
//给AttachInfo赋值
mAttachInfo = info;
...
//回调Viwe自己的onAttachedToWindow
onAttachedToWindow();
...
}
源码位置:/frameworks/base/core/java/android/view/ViewRootImpl.java
//ViewRootImpl中的getRunQueue方法
static RunQueue getRunQueue() {
RunQueue rq = sRunQueues.get();
if (rq != null) {
return rq;
}
rq = new RunQueue();
sRunQueues.set(rq);
return rq;
}
// ViewRootImpl中RunQueue
static final class RunQueue {
private final ArrayList mActions = new ArrayList();
//被View调用的post方法
void post(Runnable action) {
postDelayed(action, 0);
}
void postDelayed(Runnable action, long delayMillis) {
//封装成一个HandlerAction
HandlerAction handlerAction = new HandlerAction();
handlerAction.action = action;
handlerAction.delay = delayMillis;
synchronized (mActions) {
//存入到ArrayList中
mActions.add(handlerAction);
}
}
...
}
源码位置:/frameworks/base/core/java/android/view/ViewRootImpl.java
void executeActions(Handler handler) {
synchronized (mActions) {
//遍历集合中所有的HandlerAction
final ArrayList actions = mActions;
final int count = actions.size();
for (int i = 0; i < count; i++) {
final HandlerAction handlerAction = actions.get(i);
//使用handler发送消息
handler.postDelayed(handlerAction.action, handlerAction.delay);
}
actions.clear();
}
}
源码位置:/frameworks/base/core/java/android/view/View.java
@CallSuper
public void requestLayout() {
...
if (mParent != null && !mParent.isLayoutRequested()) {
//调用了mParent的requestLayout
mParent.requestLayout();
}
..
}
//View中的mParent赋值的方法
void assignParent(ViewParent parent) {
if (mParent == null) {
mParent = parent;
} else if (parent == null) {
mParent = null;
} else {
throw new RuntimeException("view " + this + " being added, but"
+ " it already has a parent");
}
}
源码位置:/frameworks/base/core/java/android/view/ViewGroup.java
public void addView(View child, int index, LayoutParams params) {
...
//
addViewInner(child, index, params, false);
}
private void addViewInner(View child, int index, LayoutParams params,
boolean preventRequestLayout) {
....
//设置子View的Parent为当前ViewGroup自己
if (preventRequestLayout) {
child.assignParent(this);
} else {
child.mParent = this;
}
...
}