Android疑难点解答
2016-05-10 11:02
429 查看
一.概述
这篇文章主要解答一些在平时学习工作过程中遇到的一些比较值得研究的问题。二.问题
1.DecorView是何时被创建的是在PhoneWindow的generateDecor中被创建的
protected DecorView generateDecor() { return new DecorView(getContext(), -1); }
2.ViewRootImpl是何时被创建的
是在WindowManagerGlobal的addView方法中创建的
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { //省去大量代码 ViewRootImpl root; View panelParentView = null; //省去部分代码 root = new ViewRootImpl(view.getContext(), display); ...... }
3.Activity加载布局的流程
在Activity中调用setContentView加载布局,setContentView最终调用PhoneWindow的setContentView方法,在此方法中将根布局xml文件解析成View添加到DecorView中,然后从根布局文件中找到id为contente的父容器,将我们在setContentView中指定的布局文件通过inflate的方式添加进去
//将我们的布局文件添加到mContentParent中,这个mContentParent是根布局中id为content的一个FrameLayout mLayoutInflater.inflate(layoutResID, mContentParent);
4.Window对象何时被创建
在Activity的attach方法中
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, NonConfigurationInstances lastNonConfigurationInstances, Configuration config) { attachBaseContext(context); mFragments.attachActivity(this, mContainer, null); //创建window对象 mWindow = PolicyManager.makeNewWindow(this); mWindow.setCallback(this); mWindow.getLayoutInflater().setPrivateFactory(this); if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) { mWindow.setSoftInputMode(info.softInputMode); } if (info.uiOptions != 0) { mWindow.setUiOptions(info.uiOptions); } mUiThread = Thread.currentThread(); ..... }
5.Application对象何时被创建
在Instrumentation的newApplication方法中
public Application newApplication(ClassLoader cl, String className, Context context) throws InstantiationException, IllegalAccessException, ClassNotFoundException { return newApplication(cl.loadClass(className), context); }
6.View绘制的起点在何处
当启动Activity的时候,其中有一步是执行ActivityThread的handleResumeActivity.
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) { ....... 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; wm.addView(decor, l); } .......
上面首先调用a的getWindowManager方法,其中a是Activity对象,getWindowManager获得是WindowManager对象,此处时期返回的是它的实现类WindowManagerImpl,.
然后调用了WindowManagerImpl的addView方法
@Override public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyDefaultToken(params); mGlobal.addView(view, params, mDisplay, mParentWindow); }
可以看出,WMI只是一个代理类,真正的实现实在WindowManagerGlobal中
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { ...... ViewRootImpl root; View panelParentView = null; ..... //创建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 try { //这句话很重要,将DecorView添加到ViewRootImpl中 root.setView(view, wparams, panelParentView);
然后我们看砍setView方法,
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { ..... requestLayout(); ......
这里调用了requestLayout方法,这就是View开始绘制的起点
@Override public void requestLayout() { if (!mHandlingLayoutInLayoutRequest) { checkThread(); mLayoutRequested = true; scheduleTraversals(); } }
void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); if (!mUnbufferedInputDispatch) { scheduleConsumeBatchedInput(); } notifyRendererOfFramePending(); pokeDrawLockIfNeeded(); } }
mTraversalRunnable是一个Runnable对象,此时会执行它的run方法
final class TraversalRunnable implements Runnable { @Override public void run() { doTraversal(); } } final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
void doTraversal() { if (mTraversalScheduled) { mTraversalScheduled = false; mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); if (mProfile) { Debug.startMethodTracing("ViewAncestor"); } performTraversals(); if (mProfile) { Debug.stopMethodTracing(); mProfile = false; } } }
ViewRootImpl的performTraversals方法
private void performTraversals() { //省去海量代码 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); //省去部分代码 performLayout(lp, desiredWindowWidth, desiredWindowHeight); //省去大量代码 performDraw(); ..... }
7.DecorView何时被添加到Window中
在Activity的makeVisible方法中
void makeVisible() { if (!mWindowAdded) { ViewManager wm = getWindowManager(); wm.addView(mDecor, getWindow().getAttributes()); mWindowAdded = true; } mDecor.setVisibility(View.VISIBLE); }
8.影响图片占用内存大小的因素有哪些?
(1).图片尺寸
(2)色彩细节
在Bitmap.Config中有如下定义
//8位ALPHA图 public static final Bitmap.Config ALPHA_8 //16位ARGB图,占2KB public static final Bitmap.Config ARGB_4444 //32位ARGB图,占4KB大小 public static final Bitmap.Config ARGB_8888 //16位RGB图 public static final Bitmap.Config RGB_565
9.measure方法的两个参数代表什么意思?
public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
widthMeasureSpec封装了视图的宽度大小和规格
heightMeasureSpec封装了视图的高度大小和规格
这两个参数是父视图经过计算传递下来的
我们可以通过下面的方式取出视图的大小和规格
int mode = MeasureSpec.getMode(widthMeasureSpec); int size = MeasureSpec.getSize(widthMeasureSpec);
10.父视图的widthMeasureSpec和heightMeasureSpec从哪里来?
View的绘制是从ViewRootImpl的performTraversals开始的,下面的代码定义了widthMeasureSpec和heightMeasureSpec
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width); int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
我们看看getRootMeasureSpec这个方法
/** * Figures out the measure spec for the root view in a window based on it's * layout params. * * @param windowSize * The available width or height of the window * * @param rootDimension * The layout params for one dimension (width or height) of the * window. * * @return The measure spec to use to measure the root view. */ private static int getRootMeasureSpec(int windowSize, int rootDimension) { int measureSpec; switch (rootDimension) { case ViewGroup.LayoutParams.MATCH_PARENT: // Window can't resize. Force root view to be windowSize. measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY); break; case ViewGroup.LayoutParams.WRAP_CONTENT: // Window can resize. Set max size for root view. measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST); break; default: // Window wants to be an exact size. Force root view to be that size. measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY); break; } return measureSpec; }
这个方法接收两个参数,第一个是Window的尺寸,第二个是代表WIndow尺寸的布局参数。那么看门看看这两个参数的定义
if (mWidth != frame.width() || mHeight != frame.height()) { mWidth = frame.width(); mHeight = frame.height(); }
WindowManager.LayoutParams lp = mWindowAttributes; final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
从源码我们可以看出,根布局的widthMeasureSpec中的宽度为Window的宽度,heightMeasureSpec中的高度为Window的高度,规格都是MeasureSpec.EXACTLY,也就是精确的。
11.DecorView是何时变得可见的
在ActivityThread的handleResumeActivity方法中我们可以找到答案。
if (r.window == null && !a.mFinished && willBeVisible) { r.window = r.activity.getWindow(); //获取DecorView View decor = r.window.getDecorView(); //让DecorView可见 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; //将DecorView添加到Window中 wm.addView(decor, l); }
12.View的post方法是如何做到在onCreate中获取到View的尺寸的。
public boolean post(Runnable action) { final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { return attachInfo.mHandler.post(action); } // Postpone the runnable until we know on which thread it needs to run. // Assume that the runnable will be successfully placed after attach. getRunQueue().post(action); return true; }
这里的重点在于attachInfo 何时不为空,答案是在ViewRootImpl被创建的时候,ViewRootImpl实在WindowManagerGlobal的addView方法中被创建的,而这个addView方法是在ActivityThread的handleResumeActivity中调用的。
相关文章推荐
- Android事件分发机制(一) Touch 事件的分发和消费机制
- 关于Android VerSionName版本控制问题
- 下载判断Android和iOS
- Android 二代身份证精确校验
- Android录制声音,并播放,功能优化
- Android性能优化 一 优化小结
- Android设置Toolbar的标题居中
- Android View的绘制流程
- Android 中自定义控件总结
- Android都到了4GB 为什么卡顿还存在?
- Android知识点收集
- Android ExpandableLayout:一种可伸缩扩展的Layout
- ANDROID基础
- Android 5.1外置存储卡文件无法删除
- Android 在屏幕上打印LOG
- android广告轮播(循环滑动,定时滑动,动态加载indicator)
- Android 编程下获得应用程序的签名
- Android ——对HandlerThread的理解和注意事项
- Android中图片的常识(一)
- Android内存泄漏