Android源碼之Activity從啟動到顯示到界面

前言:

在上兩篇文章中對setContentView()是如何將我們的內(nèi)容視圖添加到系統(tǒng)提供的根視圖中以及PhoneWindow的創(chuàng)建等做了粗略的分析,且這個時候內(nèi)容視圖還完全處于內(nèi)存中 我們是還看不見的,本篇趁熱打鐵繼續(xù)跟進 將要了解Activity是如何將DecorView添加到Window中 以及是如何將DecorView繪制到屏幕上的

分析要點:

老規(guī)矩 先來張Activity啟動流程圖:


都知道系統(tǒng)源碼中有一個全局的Handler 不管是Activity的啟動還是Service的啟動或綁定 亦或廣播的注冊 都會由它發(fā)送消息處理,而這個Handler對消息的處理就在ActivityThread類中 本文也將從ActivityThread中著手去分析Activity啟動后生命周期是如何執(zhí)行的蚣驼。

源碼閱讀:

因?qū)τ趕tartActivity()和通過Launch啟動App的啟動流程尚且不熟悉 所以這里直接跳到Activity已經(jīng)開始啟動的流程著手分析 首先來到ActivityThread#handleLaunchActivity() 所有Activity的啟動都會調(diào)用這里 同時也會只撿要緊的函數(shù)看

 private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        unscheduleGcIdler();
        mSomeActivitiesChanged = true;
        if (r.profilerInfo != null) {
            mProfiler.setProfiler(r.profilerInfo);
            mProfiler.startProfiling();
        }
        // Make sure we are running with the most recent config.
        handleConfigurationChanged(null, null);

        // WindowManagerGlobal初始化工作 這個WindowManagerGlobal是非常重要的一個類
        WindowManagerGlobal.initialize();
        
        //Activity就是在這里創(chuàng)建的
        Activity a = performLaunchActivity(r, customIntent);

        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            Bundle oldState = r.state;

            //Activity的onResume() 以及內(nèi)容視圖的繪制就是從這個函數(shù)開始的
            handleResumeActivity(r.token, false, r.isForward,!r.activity.mFinished && !r.startsNotResumed);
        }
}

先看Activity是如何創(chuàng)建的

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ActivityInfo aInfo = r.activityInfo;
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }
        ComponentName component = r.intent.getComponent();
        if (component == null) {
            component = r.intent.resolveActivity(
                mInitialApplication.getPackageManager());
            r.intent.setComponent(component);
        }

        if (r.activityInfo.targetActivity != null) {
            component = new ComponentName(r.activityInfo.packageName,
                    r.activityInfo.targetActivity);
        }
        //這里通過反射的方式創(chuàng)建Activity
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
        }

        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
            if (activity != null) {
                Context appContext = createBaseContextForActivity(r, activity);
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);

                //這里調(diào)用了activity#attach()進行PhoneWindow的創(chuàng)建以及一些Cllback監(jiān)聽的初始化和非常重要的WindowManagerImpl初始化等操作
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor);

                if (customIntent != null) {
                    activity.mIntent = customIntent;
                }
                r.lastNonConfigurationInstances = null;
                activity.mStartedActivity = false;
                int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme);
                }

                activity.mCalled = false;
                
                //Activity的onCreate()這里被調(diào)用 區(qū)別就是參數(shù)不同
                if (r.isPersistable()) {    
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                r.activity = activity;
                r.stopped = true;
                
                //Activity的onStart()在這里被調(diào)用
                if (!r.activity.mFinished) {
                    activity.performStart();
                    r.stopped = false;
                }
                .................................
        return activity;
    }

mInstrumentation.callActivityOnCreate()Activtiy#onCreate()和Activity#onStart()

//這個Instrumentation類似于AppCompatActivity中的AppCompatDelegate一樣是一個代理類
public class Instrumentation {

public void callActivityOnCreate(Activity activity, Bundle icicle) {
        prePerformCreate(activity);
        //onCreate()
        activity.performCreate(icicle);
        postPerformCreate(activity);
    }
    //Activity#onStart()
public void callActivityOnStart(Activity activity) {
        activity.onStart();
    }
} 
 .................分割線................
 
// 跟進activity.performCreate(icicle)
 
class Activity{
    //一個參數(shù)
    final void performCreate(Bundle icicle) {
        restoreHasCurrentPermissionRequest(icicle);
        //執(zhí)行OnonCreate()
        onCreate(icicle);
        mActivityTransitionState.readState(icicle);
        performCreateCommon();
    }
    //2個參數(shù)
    final void performCreate(Bundle icicle, PersistableBundle persistentState) {
        restoreHasCurrentPermissionRequest(icicle);
        //執(zhí)行OnonCreate()
        onCreate(icicle, persistentState);
        mActivityTransitionState.readState(icicle);
        performCreateCommon();
    }
    
     final void performStart() {
        mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
        mFragments.noteStateNotSaved();
        mCalled = false;
        mFragments.execPendingActions();

        //通過調(diào)用Instrumentation類的callActivityOnStart執(zhí)行OnStart()
        mInstrumentation.callActivityOnStart(this);
        mFragments.dispatchStart();
        mFragments.reportLoaderStart();
        ........
    }
}

Activity創(chuàng)建好了 并且也執(zhí)行到onStart() 再返回去看Activity的onResume()以及內(nèi)容視圖的繪制過程

final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume) {
        unscheduleGcIdler();
        mSomeActivitiesChanged = true;

        // Activity#onResume()在這里執(zhí)行 且此時內(nèi)容還未繪制 也驗證了onResume()后視圖可見 是一個錯誤的觀念 至少需要等一會
        ActivityClientRecord r = performResumeActivity(token, clearHide);
        
        /*****************重點將從這里開始**************************/
        
       if (r.window == null && !a.mFinished && willBeVisible) {
                //獲取Activity中創(chuàng)建的Window對象
                r.window = r.activity.getWindow();
                
                //獲取Window中的DecorView
                View decor = r.window.getDecorView();
                
                //INVISIBLE雖然不可見 但是卻能占據(jù)window空間
                decor.setVisibility(View.INVISIBLE);
                
                //這里獲取WindowManager的實現(xiàn)類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;

                    //這一步執(zhí)行將DecorView添加到Window窗口中和針對DecorView的測量 布局 繪制操作
                    wm.addView(decor, l);
                }
            }
            
            .................... 
  }

先看Activity的onResume()是如何執(zhí)行的

public final ActivityClientRecord performResumeActivity(IBinder token,
            boolean clearHide) {
        ............
                //onResume()在這里被執(zhí)行
                r.activity.performResume();
        ............
        
        return r;
    }

DecorView是如何添加到Window中的财异? 且WindowManagerImpl是在Activity#attach()時初始化的 就要從WindowManagerImpl類開始分析 上面也是調(diào)用的 WindowManagerImpl的addView()

public final class WindowManagerImpl implements WindowManager {

//WindowManagerGlobal
 private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
 
 @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }
}   

 /*******************WindowManagerGlobal************************/
public final class WindowManagerGlobal {
    //這里聲明一些集合 來緩存我們加載過的view 在下次使用的時候 見會提高程序的執(zhí)行速度

    private final ArrayList<View> mViews = new ArrayList<View>();
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
    private final ArrayList<WindowManager.LayoutParams> mParams =
            new ArrayList<WindowManager.LayoutParams>();
            
  public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        
        if (parentWindow != null) { 
    parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } 
        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {
            // Start watching for system property changes.
            if (mSystemPropertyUpdater == null) {
                mSystemPropertyUpdater = new Runnable() {
                    @Override public void run() {
                        synchronized (mLock) {
                            for (int i = mRoots.size() - 1; i >= 0; --i) {
                                mRoots.get(i).loadSystemProperties();
                            }
                        }
                    }
                };
                SystemProperties.addChangeCallback(mSystemPropertyUpdater);
            }

            
            mRoots.get(index).doDie();
           
            root = new ViewRootImpl(view.getContext(), display);

            view.setLayoutParams(wparams);
            //這個view就是DecorView
            mViews.add(view);
            //ViewRootImpl 繪制好了View
            mRoots.add(root);
            //Window#Params
            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.
            synchronized (mLock) {
                final int index = findViewLocked(view, false);
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
            }
            throw e;
        }
}

繼續(xù)深入 ViewRootImpl.setView()

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
             ...........................................
                //執(zhí)行繪制操作
                requestLayout();
                if ((mWindowAttributes.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                    mInputChannel = new InputChannel();
                }
                try {
                    mOrigWindowType = mWindowAttributes.type;
                    mAttachInfo.mRecomputeGlobalAttributes = true;
                    collectViewAttributes();

                    //這里使用IPC WMS將完成窗口的添加過程 這塊我也不太下熟悉就跳過了
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
                } 
           //這句代碼也很重要 將ViewRootImpl設(shè)置為DecorView的 ViewParent                
           view.assignParent(this);

}                

requestLayout()繪制流程

@Override
public void requestLayout() {
     if (!mHandlingLayoutInLayoutRequest) {
          checkThread();
          mLayoutRequested = true;
          scheduleTraversals();
     }
 }
 
void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();

            //Choreographer類中有一個Handler通過發(fā)送消息執(zhí)行TraversalRunnable的run()方法
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
} 

final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    } 
    
 void doTraversal() {
            .........      
            performTraversals();
            ..........
    }
//到這函數(shù) 針對DecorView的測量 布局 繪制 都將完成    
private void performTraversals() {
    .............
    if (!mStopped || mReportNextDraw) {
      //確定測量模式和測量規(guī)格
       boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
       (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
       if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
       || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
       int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
       int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);

                    
      //將調(diào)用DecorView的Measure()
      performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
    }
     //將調(diào)用DecorView的Layout()
     performLayout(lp, desiredWindowWidth, desiredWindowHeight);
     
     //將調(diào)用DecorView的Draw()
     performDraw();
}                             

測量 布局 繪制完成 再通過WMS完成窗口的添加過程 到此DecorView才真正顯示到我們的屏幕上了


最后再多看一眼view.assignParent(this);將ViewRootImpl設(shè)置為DecorView的 ViewParent 這樣的目的是什么

class View{

    void assignParent(ViewParent parent) {
        if (mParent == null) {
            mParent = parent;
        } else if (parent == null) {
            mParent = null;
    }  
    //當(dāng)我們調(diào)用View的 requestLayout()
    @CallSuper
    public void requestLayout() {
        if (mMeasureCache != null) mMeasureCache.clear();

        if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) {
            // Only trigger request-during-layout logic if this is the view requesting it,
            // not the views in its parent hierarchy
            ViewRootImpl viewRoot = getViewRootImpl();
            if (viewRoot != null && viewRoot.isInLayout()) {
                if (!viewRoot.requestLayoutDuringLayout(this)) {
                    return;
                }
            }
            mAttachInfo.mViewRequestingLayout = this;
        }

        mPrivateFlags |= PFLAG_FORCE_LAYOUT;
        mPrivateFlags |= PFLAG_INVALIDATED;

        if (mParent != null && !mParent.isLayoutRequested()) {
            //將會一直獲取到父容器的 mParent.requestLayout();
            mParent.requestLayout();
        }
    }          
}

到這里就很明白了平時我們在調(diào)用View的requestLayout()進行重新測量 布局 繪制時 會一直走到 ViewRootImpl的requestLayout()函數(shù)將DecorView重新測量 布局 繪制 由此看出在不是很必要的情況下不能直接調(diào)用該函數(shù)來刷新視圖 因為這個過程是很耗CUP的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末茎用,一起剝皮案震驚了整個濱河市炉抒,隨后出現(xiàn)的幾起案子署穗,更是在濱河造成了極大的恐慌东羹,老刑警劉巖个榕,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異概耻,居然都是意外死亡使套,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門鞠柄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來侦高,“玉大人,你說我怎么就攤上這事厌杜》钋海” “怎么了?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵夯尽,是天一觀的道長瞧壮。 經(jīng)常有香客問我,道長匙握,這世上最難降的妖魔是什么咆槽? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮圈纺,結(jié)果婚禮上秦忿,老公的妹妹穿的比我還像新娘。我一直安慰自己蛾娶,他們只是感情好灯谣,可當(dāng)我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蛔琅,像睡著了一般胎许。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天呐萨,我揣著相機與錄音杀饵,去河邊找鬼。 笑死谬擦,一個胖子當(dāng)著我的面吹牛切距,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播惨远,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼谜悟,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了北秽?” 一聲冷哼從身側(cè)響起葡幸,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贺氓,沒想到半個月后蔚叨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡辙培,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年蔑水,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扬蕊。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡搀别,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出尾抑,到底是詐尸還是另有隱情歇父,我是刑警寧澤,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布再愈,位于F島的核電站榜苫,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏翎冲。R本人自食惡果不足惜单刁,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望府适。 院中可真熱鬧,春花似錦肺樟、人聲如沸檐春。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽疟暖。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間俐巴,已是汗流浹背骨望。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留欣舵,地道東北人擎鸠。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像缘圈,于是被迫代替她去往敵國和親劣光。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,689評論 2 354

推薦閱讀更多精彩內(nèi)容