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

哈哈,一起学习:)

这里会从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 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 ….

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值