onCreate()中getHeight()獲取不到高度的原因(源碼分析)

問題

在Activity的週期方法onCreate()調用getHeight()爲什麼返回值爲0?那在onResume()方法中可以獲取到嗎?那調用getMeasureHeight()可以獲取到值嗎?我們從源碼分析一下。

Activity啓動簡述

其實,這裏就涉及到Activity啓動流程的問題,要點就是Activity.onCreate()/onStart()/onResume()等生命週期方法和view的繪製哪一個先執行。那麼我們就從activity啓動流程作爲切入口來探究。ActivityThread.main()方法中通過binder通信與AMS取得聯繫,綁定application。AMS接收到請求後,會調用attachApplicationLocked()方法,其中第一步調用ApplicationThread.bindApplication()進行application綁定,第二步調用ApplicationThread.attachApplicationLocked()啓動activity。ApplicationThread收到後最終會調用到ActivityThread.handleLaunchActivity()中,此時,應用進程就要真正開始啓動activity。隨後又會調用ActivityThread.handleResumeActivity()開始展示activity,以上是activity啓動的簡述,沒看過activity啓動的同學可能會不理解,建議學習一下。

handleResumeActivity方法

handleResumeActivity這個方法是我們重點關注的方法,在這個方法中,會將DecorView添加到window中。而添加之後,就會進行View的繪製。在調用handleResumeActivity之前,handleLaunchActivity中已經通過儀表盤創建了activity並調用了onCreate()方法,所以,在onCreate()中getMeasureHeight()/getHeight()獲取爲0。那麼在onResume()方法中會獲取到值嗎?答案就在handleResumeActivity()方法中,如下:

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

        // TODO Push resumeArgs into the activity for consideration
        //調用performReusmeActivity,其中會調用activity.onResume()
        ActivityClientRecord r = performResumeActivity(token, clearHide);

         ......
        if (r != null) {
            final Activity a = r.activity;
            if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow();
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) {
                    a.mWindowAdded = true;
                    //將decorView添加到window中,這也是View繪製開始的起點
                    wm.addView(decor, l);
                }
        }
}        

可以清楚的看到,performResumeActivity()調用在wm.addView()之前,所以在onResume()中是獲取不到高度的。

performResumeActivity()如下:

public final ActivityClientRecord performResumeActivity(IBinder token,
           boolean clearHide) {
       ActivityClientRecord r = mActivities.get(token);
       if (r != null && !r.activity.mFinished) {
           if (clearHide) {
               r.hideForNow = false;
               r.activity.mStartedActivity = false;
           }
           try {
               r.activity.onStateNotSaved();
               ....
               r.activity.performResume();
               ....
           } catch (Exception e) {
              ....
           }
       }
       return r;
   }

調用activity.performResume(),其中會通過儀表盤調用onResume():

後邊的代碼就不貼了,有興趣的同學可以查看源碼。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章