美文网首页
源码分析-从ActivityThread到View绘制流程

源码分析-从ActivityThread到View绘制流程

作者: 半只温柔 | 来源:发表于2018-01-26 17:42 被阅读0次

    哈哈,一起学习:)

    这里会从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<T>:
    百度百科:
    JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。
    JDK 5.0中,ThreadLocal已经支持泛型,该类的类名已经变为ThreadLocal<T>。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 nextHashCode() {
            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 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 ....

    相关文章

      网友评论

          本文标题:源码分析-从ActivityThread到View绘制流程

          本文链接:https://www.haomeiwen.com/subject/xzbiaxtx.html