源码分析-从ActivityThread到View绘制流程
2018-01-30 14:01
429 查看
哈哈,一起学习:)
这里会从ActivityThread开始分析,也有必要过一下,最后会整个流程会走一遍,主线一定要走~~
开始: core/java/android/app/ActivityThread.java
(Trace和Log的原理这里就不走了,涉及到了linux-system层的一些架构之后再看)
这里我们看一下Looper.prepareMainLooper()方法 —>Loop.java这里把Looper.java贴出来了,也没多大
发现在prepare里将初始化了的Looper(MessageQueue不能被强行终止)给了ThreadLocal —>prepare方法如下:
注意了:prepare(false)是私有的,不能被外部调用,只被主线程调用。
Looper的私有构造:
发现quitAllowed标志量传入了MessageQueue。MessageQueue是由内部的Message采用指针方式实现的链表,内部有个quit(boolean safe)方法如下:
这里就说明了我们的UI线程不能主动,强制退出消息循环
————————————————————————————————————————————————
扩展:)可忽略
需要了解ThreadLocal:
百度百科:
JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。
JDK 5.0中,ThreadLocal已经支持泛型,该类的类名已经变为ThreadLocal。API方法也相应进行了调整,新版本的API方法分别是void set(T value)、T get()以及T initialValue()。
可以看出ThreadLocal里有ThreadLocalMap,也就是相当于一个map,这个map不同寻常,既然敢说解决并发,肯定有特殊的地方——-对于多线程资源共享的问题,synchronized同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。synchronized同步机制仅提供一份变量,让不同的线程排队访问,而ThreadLocal为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
将HashCode原子性的integer作为key值,1:AtomicInteger的volatile(保证主存数据更新,去除指令重排的内存优化)保证了并发的有序性 2:通过sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe()+获取期望值CAS算法保证了并发原子性。
—————————————————————————————————————————————
哈哈,回到prepareMainLooper,先不考虑
AMS.startProcessLocked()–>Process.start()–>zygoteSendArgsAndGetResult()–>ZygoteInit.invokeStaticMain(cloader, className, mainArgs)(ActivityThread.main)
此时的线程,也就是我们的UI线程 ,然后看 attach 方法
ActivityThread.attach
上面我们会对2个地方产生兴趣
1:IActivityManager对象(ActivityManager的代理对象),执行attachApplication(mAppThread ),mAppThread 是什么?(这里涉及到的下篇文章)
2:ViewRootImpl对象添加addFirstDrawHandler和ConfigChangedCallback的回掉(这个类一会儿分析吧)
回到我们的main方法, Looper.loop();让消息机制执行
死循环保证了线程(程序)不会退出,app一直运行下去。通过attach(false)方法会创建新的线程ApplicationThread(这是一个binder用于接收AMS发来的事件,下篇文章见——–Activity的启动及启动模式),这里只要了解ActivityThread里通过消息机制可以接收处理Activity的生命周期方法,
ActivityThread类会调用handleResumeActivity
vm是个接口,我们看实现类WindowManagerImpl的addView方法
发现mGlobal对象做了addView处理
root.setView, — ViewRootImpl.java
接下来进入到performTraversals方法:
我们看到了view.measure,下篇我们开始View的绘制流程
有点遗憾,随后再编辑。
之后是Activity启动流程,Window相关,Surface-SurfaceHolder-SurfaceView ….
这里会从ActivityThread开始分析,也有必要过一下,最后会整个流程会走一遍,主线一定要走~~
开始: core/java/android/app/ActivityThread.java
1: ActivityThread.java
这个java文件并没有构造方法,有的是public static void main(String[] args),也就是通常意义的app入口(Trace和Log的原理这里就不走了,涉及到了linux-system层的一些架构之后再看)
public static void main(String[] args) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain"); //dalvik.system;CloseGuard是一种标记隐式终结器清理资源的机制,应该通过显式的关闭方法 //(又称Effective Java中的“显式终止方法”)清理资源。 //CloseGuard默认为true,可能相当垃圾. //我们在这里禁用它,但有选择地启用它(通过 StrictMode)调试版本,但使用DropBox,不是日志。 CloseGuard.setEnabled(false); //初始化文件系统 -- >new出user的UserEnvironment对象(通过Stub代理可获取StorageManager) Environment.initForCurrentUser(); // Set the reporter for event logging in libcore EventLogger.setReporter(new EventLoggingReporter()); // Make sure TrustedCertificateStore looks in the right place for CA certificates final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId()); TrustedCertificateStore.setDefaultUserDirectory(configDir); Process.setArgV0("<pre-initialized>"); //创建Looper和MessageQueue对象,用于处理主线程的消息 Looper.prepareMainLooper(); //创建ActivityThread对象 ActivityThread thread = new ActivityThread(); //建立Binder通道 (创建新线程) thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } // End of event ActivityThreadMain. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); //消息循环运行 Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }
这里我们看一下Looper.prepareMainLooper()方法 —>Loop.java这里把Looper.java贴出来了,也没多大
public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }
发现在prepare里将初始化了的Looper(MessageQueue不能被强行终止)给了ThreadLocal —>prepare方法如下:
private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); }
注意了:prepare(false)是私有的,不能被外部调用,只被主线程调用。
Looper的私有构造:
private Looper(boolean quitAllowed) { // quitAllowed --- True if the message queue can be quit. mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
发现quitAllowed标志量传入了MessageQueue。MessageQueue是由内部的Message采用指针方式实现的链表,内部有个quit(boolean safe)方法如下:
void quit(boolean safe) { if (!mQuitAllowed) { throw new IllegalStateException("Main thread not allowed to quit."); } synchronized (this) { if (mQuitting) { return; } mQuitting = true; if (safe) { removeAllFutureMessagesLocked(); } else { removeAllMessagesLocked(); } // We can assume mPtr != 0 because mQuitting was previously false. nativeWake(mPtr); } }
这里就说明了我们的UI线程不能主动,强制退出消息循环
————————————————————————————————————————————————
扩展:)可忽略
需要了解ThreadLocal:
百度百科:
JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。
JDK 5.0中,ThreadLocal已经支持泛型,该类的类名已经变为ThreadLocal。API方法也相应进行了调整,新版本的API方法分别是void set(T value)、T get()以及T initialValue()。
public class ThreadLocal<T> { private final int threadLocalHashCode = nextHashCode(); private static AtomicInteger nextHashCode = new AtomicInteger(); private static final int HASH_INCREMENT = 0x61c88647; private static int nextHashCo 4000 de() { return nextHashCode.getAndAdd(HASH_INCREMENT); } protected T initialValue() { return null; } public ThreadLocal() { } public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } return setInitialValue(); } private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; } public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); } ThreadLocalMap getMap(Thread t) { return t.threadLocals; } void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); } static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) { return new ThreadLocalMap(parentMap); } T childValue(T parentValue) { throw new UnsupportedOperationException(); } static class ThreadLocalMap { static class Entry extends WeakReference<ThreadLocal> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal k, Object v) { super(k); value = v; } } private static final int INITIAL_CAPACITY = 16; private Entry[] table; private int size = 0; private int threshold; // Default to 0 private void setThreshold(int len) { threshold = len * 2 / 3; } private static int nextIndex(int i, int len) { return ((i + 1 < len) ? i + 1 : 0); } private static int prevIndex(int i, int len) { return ((i - 1 >= 0) ? i - 1 : len - 1); } ThreadLocalMap(ThreadLocal firstKey, Object firstValue) { table = new Entry[INITIAL_CAPACITY]; int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); table[i] = new Entry(firstKey, firstValue); size = 1; setThreshold(INITIAL_CAPACITY); } private ThreadLocalMap(ThreadLocalMap parentMap) { Entry[] parentTable = parentMap.table; int len = parentTable.length; setThreshold(len); table = new Entry[len]; for (int j = 0; j < len; j++) { Entry e = parentTable[j]; if (e != null) { ThreadLocal key = e.get(); if (key != null) { Object value = key.childValue(e.value); Entry c = new Entry(key, value); int h = key.threadLocalHashCode & (len - 1); while (table[h] != null) h = nextIndex(h, len); table[h] = c; size++; } } } } private Entry getEntry(ThreadLocal key) { int i = key.threadLocalHashCode & (table.length - 1); Entry e = table[i]; if (e != null && e.get() == key) return e; else return getEntryAfterMiss(key, i, e); } private Entry getEntryAfterMiss(ThreadLocal key, int i, Entry e) { Entry[] tab = table; int len = tab.length; while (e != null) { ThreadLocal k = e.get(); if (k == key) return e; if (k == null) expungeStaleEntry(i); else i = nextIndex(i, len); e = tab[i]; } return null; } private void set(ThreadLocal key, Object value) { Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1); for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { ThreadLocal k = e.get(); if (k == key) { e.value = value; return; } if (k == null) { replaceStaleEntry(key, value, i); return; } } tab[i] = new Entry(key, value); int sz = ++size; if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash(); } private void remove(ThreadLocal key) { Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1); for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { if (e.get() == key) { e.clear(); expungeStaleEntry(i); return; } } } private void replaceStaleEntry(ThreadLocal key, Object value, int staleSlot) { Entry[] tab = table; int len = tab.length; Entry e; int slotToExpunge = staleSlot; for (int i = prevIndex(staleSlot, len); (e = tab[i]) != null; i = prevIndex(i, len)) if (e.get() == null) slotToExpunge = i; for (int i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) { ThreadLocal k = e.get(); if (k == key) { e.value = value; tab[i] = tab[staleSlot]; tab[staleSlot] = e; if (slotToExpunge == staleSlot) slotToExpunge = i; cleanSomeSlots(expungeStaleEntry(slotToExpunge), len); return; } if (k == null && slotToExpunge == staleSlot) slotToExpunge = i; } tab[staleSlot].value = null; tab[staleSlot] = new Entry(key, value); if (slotToExpunge != staleSlot) cleanSomeSlots(expungeStaleEntry(slotToExpunge), len); } private int expungeStaleEntry(int staleSlot) { Entry[] tab = table; int len = tab.length; tab[staleSlot].value = null; tab[staleSlot] = null; size--; Entry e; int i; for (i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) { ThreadLocal k = e.get(); if (k == null) { e.value = null; tab[i] = null; size--; } else { int h = k.threadLocalHashCode & (len - 1); if (h != i) { tab[i] = null; // Unlike Knuth 6.4 Algorithm R, we must scan until // null because multiple entries could have been stale. while (tab[h] != null) h = nextIndex(h, len); tab[h] = e; } } } return i; } private boolean cleanSomeSlots(int i, int n) { boolean removed = false; Entry[] tab = table; int 11a59 len = tab.length; do { i = nextIndex(i, len); Entry e = tab[i]; if (e != null && e.get() == null) { n = len; removed = true; i = expungeStaleEntry(i); } } while ( (n >>>= 1) != 0); return removed; } private void rehash() { expungeStaleEntries(); if (size >= threshold - threshold / 4) resize(); } private void resize() { Entry[] oldTab = table; int oldLen = oldTab.length; int newLen = oldLen * 2; Entry[] newTab = new Entry[newLen]; int count = 0; for (int j = 0; j < oldLen; ++j) { Entry e = oldTab[j]; if (e != null) { ThreadLocal k = e.get(); if (k == null) { e.value = null; // Help the GC } else { int h = k.threadLocalHashCode & (newLen - 1); while (newTab[h] != null) h = nextIndex(h, newLen); newTab[h] = e; count++; } } } setThreshold(newLen); size = count; table = newTab; } private void expungeStaleEntries() { Entry[] tab = table; int len = tab.length; for (int j = 0; j < len; j++) { Entry e = tab[j]; if (e != null && e.get() == null) expungeStaleEntry(j); } } } }
可以看出ThreadLocal里有ThreadLocalMap,也就是相当于一个map,这个map不同寻常,既然敢说解决并发,肯定有特殊的地方——-对于多线程资源共享的问题,synchronized同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。synchronized同步机制仅提供一份变量,让不同的线程排队访问,而ThreadLocal为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
将HashCode原子性的integer作为key值,1:AtomicInteger的volatile(保证主存数据更新,去除指令重排的内存优化)保证了并发的有序性 2:通过sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe()+获取期望值CAS算法保证了并发原子性。
—————————————————————————————————————————————
哈哈,回到prepareMainLooper,先不考虑
AMS.startProcessLocked()–>Process.start()–>zygoteSendArgsAndGetResult()–>ZygoteInit.invokeStaticMain(cloader, className, mainArgs)(ActivityThread.main)
此时的线程,也就是我们的UI线程 ,然后看 attach 方法
ActivityThread.attach
private void attach(boolean system) { // private static volatile ActivityThread sCurrentActivityThread; sCurrentActivityThread = this; // boolean mSystemThread = false; mSystemThread = system; if (!system) { //对view进行初始化操作而进行添加的一个处理的handler对象,有人对ViewRootImpl的理解是一个handler对象来处理view相关的方法 ViewRootImpl.addFirstDrawHandler(new Runnable() { @Override public void run() { //在实时 (JIT) 编译器开始编译函数时,将激活 jitCompilationStart 托管调试助手 (MDA) 来报告此情况。 ensureJitEnabled(); } }); android.ddm.DdmHandleAppName.setAppName("<pre-initialized>", UserHandle.myUserId()); RuntimeInit.setApplicationObject(mAppThread.asBinder()); //获得IActivityManager的一个实例,IActivityManager其实算是一个binder对象,负责跟底层沟通 final IActivityManager mgr = ActivityManager.getService(); try { // final ApplicationThread mAppThread = new ApplicationThread(); mgr.attachApplication(mAppThread); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } // 添加GC监察者 BinderInternal.addGcWatcher(new Runnable() { @Override public void run() { if (!mSomeActivitiesChanged) { return; } Runtime runtime = Runtime.getRuntime(); long dalvikMax = runtime.maxMemory(); long dalvikUsed = runtime.totalMemory() - runtime.freeMemory(); if (dalvikUsed > ((3*dalvikMax)/4)) { if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024) + " total=" + (runtime.totalMemory()/1024) + " used=" + (dalvikUsed/1024)); mSomeActivitiesChanged = false; try { mgr.releaseSomeActivities(mAppThread); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } }); } else { // Don't set application object here -- if the system crashes, // we can't display an alert, we just want to die die die. android.ddm.DdmHandleAppName.setAppName("system_process", UserHandle.myUserId()); try { mInstrumentation = new Instrumentation(); ContextImpl context = ContextImpl.createAppContext( this, getSystemContext().mPackageInfo); mInitialApplication = context.mPackageInfo.makeApplication(true, null); mInitialApplication.onCreate(); } catch (Exception e) { throw new RuntimeException( "Unable to instantiate Application():" + e.toString(), e); } } // add dropbox logging to libcore DropBox.setReporter(new DropBoxReporter()); //ViewRootImpl的ConfigChangedCallback ViewRootImpl.ConfigChangedCallback configChangedCallback = (Configuration globalConfig) -> { synchronized (mResourcesManager) { // We need to apply this change to the resources immediately, because upon returning // the view hierarchy will be informed about it. if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig, null /* compat */)) { updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(), mResourcesManager.getConfiguration().getLocales()); // This actually changed the resources! Tell everyone about it. if (mPendingConfiguration == null || mPendingConfiguration.isOtherSeqNewer(globalConfig)) { mPendingConfiguration = globalConfig; sendMessage(H.CONFIGURATION_CHANGED, globalConfig); } } } }; ViewRootImpl.addConfigCallback(configChangedCallback); }
上面我们会对2个地方产生兴趣
1:IActivityManager对象(ActivityManager的代理对象),执行attachApplication(mAppThread ),mAppThread 是什么?(这里涉及到的下篇文章)
2:ViewRootImpl对象添加addFirstDrawHandler和ConfigChangedCallback的回掉(这个类一会儿分析吧)
回到我们的main方法, Looper.loop();让消息机制执行
public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // This must be in a local variable, in case a UI event sets the logger final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } final long traceTag = me.mTraceTag; if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } try { msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } // Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } msg.recycleUnchecked(); } }
死循环保证了线程(程序)不会退出,app一直运行下去。通过attach(false)方法会创建新的线程ApplicationThread(这是一个binder用于接收AMS发来的事件,下篇文章见——–Activity的启动及启动模式),这里只要了解ActivityThread里通过消息机制可以接收处理Activity的生命周期方法,
ActivityThread类会调用handleResumeActivity
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) { ActivityClientRecord r = mActivities.get(token); if (!checkAndUpdateLifecycleSeq(seq, r, "resumeActivity")) { return; } // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); mSomeActivitiesChanged = true; // TODO Push resumeArgs into the activity for consideration r = performResumeActivity(token, clearHide, reason); .... //ActivityClientRecord if (r.window == null && !a.mFinished && willBeVisible) { //获得当前Activity的Window对象 r.window = r.activity.getWindow(); //获得当前DecorView对象 View decor = r.window.getDecorView(); decor.setVisibility(View.INVISIBLE); //得当当前Activity的WindowManagerImpl对象 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添加到当前Activity的窗口上面 wm.addView(decor, l); ....
vm是个接口,我们看实现类WindowManagerImpl的addView方法
@Override public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyDefaultToken(params); //private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();单例模式 mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow); }
发现mGlobal对象做了addView处理
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { .... ViewRootImpl root; View panelParentView = null; .... 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 { root.setView(view, wparams, panelParentView); } catch (RuntimeException e) { // BadTokenException or InvalidDisplayException, clean up. if (index >= 0) { removeViewLocked(index, true); } throw e; } } }
root.setView, — ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { synchronized (this) { if (mView == null) { //将顶层视图DecorView赋值给全局的mView mView = view; .... //标记已添加DecorView mAdded = true; .... //请求布局 requestLayout(); .... } } @Override public void requestLayout() { if (!mHandlingLayoutInLayoutRequest) { checkThread(); mLayoutRequested = true; scheduleTraversals(); } } .... void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; mTraversalBarrier = mHandler.getLooper().postSyncBarrier(); mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); if (!mUnbufferedInputDispatch) { scheduleConsumeBatchedInput(); } notifyRendererOfFramePending(); } } .... final class TraversalRunnable implements Runnable { @Override public void run() { doTraversal(); } } final TraversalRunnable mTraversalRunnable = new TraversalRunnable(); .... void doTraversal() { if (mTraversalScheduled) { mTraversalScheduled = false; mHandler.getLooper().removeSyncBarrier(mTraversalBarrier); try { performTraversals(); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } } } ....
接下来进入到performTraversals方法:
private void performTraversals() { // cache mView since it is used so much below... //setView方法将DecorView赋值给mView final View host = mView; //在Step3 成员变量mAdded赋值为true,因此条件不成立 if (host == null || !mAdded) return; //是否正在遍历 mIsInTraversal = true; //是否马上绘制View mWillDrawSoon = true; .... //顶层视图DecorView所需要窗口的宽度和高度 int desiredWindowWidth; int desiredWindowHeight; .... //在构造方法中mFirst已经设置为true,表示是否是第一次绘制DecorView if (mFirst) { mFullRedrawNeeded = true; mLayoutRequested = true; //如果窗口的类型是有状态栏的,那么顶层视图DecorView所需要窗口的宽度和高度就是除了状态栏 if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) { // NOTE -- system code, won't try to do compat mode. Point size = new Point(); mDisplay.getRealSize(size); desiredWindowWidth = size.x; desiredWindowHeight = size.y; } else {//否则顶层视图DecorView所需要窗口的宽度和高度就是整个屏幕的宽高 DisplayMetrics packageMetrics = mView.getContext().getResources().getDisplayMetrics(); desiredWindowWidth = packageMetrics.widthPixels; desiredWindowHeight = packageMetrics.heightPixels; } } .... //获得view宽高的测量规格,mWidth和mHeight表示窗口的宽高,lp.widthhe和lp.height表示DecorView根布 局宽和高 int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width); int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height); // Ask host how big it wants to be //执行测量操作 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); .... //执行布局操作 performLayout(lp, desiredWindowWidth, desiredWindowHeight); .... //执行绘制操作 performDraw(); } .... private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) { if (mView == null) { return; } Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure"); try { mView.measure(childWidthMeasureSpec, childHeightMeasureSpec); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } } ....
我们看到了view.measure,下篇我们开始View的绘制流程
有点遗憾,随后再编辑。
之后是Activity启动流程,Window相关,Surface-SurfaceHolder-SurfaceView ….
相关文章推荐
- Android应用层View绘制流程与源码分析
- Android应用层View绘制流程与源码分析
- Android应用层View绘制流程与源码分析
- Android应用层View绘制流程与源码分析(转)
- Android应用层View绘制流程与源码分析
- Android应用层View绘制流程与源码分析
- Android应用层View绘制流程与源码分析
- View的源码分析(绘制流程以及刷新机制)
- Android应用层View绘制流程与源码分析
- Android应用层View绘制流程与源码分析
- Android应用层View绘制流程与源码分析
- View绘制流程与源码分析
- Android笔记--View绘制流程源码分析(一)
- Android笔记--View绘制流程源码分析(二)
- Android View 绘制流程 与invalidate 和postInvalidate 分析--从源码角度
- Android应用层View绘制流程与源码分析
- Android应用层View绘制流程与源码分析
- Android应用层View绘制流程与源码分析
- Android View绘制流程(结合源码分析)上
- Android应用层View绘制流程与源码分析