03.Android之View原理問題

目錄介紹

  • 3.0.0.1 View的繪製須要通過哪些過程?有哪些經常使用回調方法?View的繪製流程的詳細流程是怎樣的?
  • 3.0.0.2 View繪製流程,當一個TextView的實例調用setText()方法後執行了什麼?請說一下原理……
  • 3.0.0.3 requestLayout()、invalidate()與postInvalidate()有什麼區別?
  • 3.0.0.4 DecorView的做用是什麼?DecorView中如何獲取ContentView以及Activity所設置的View?ViewRootIml如何和DecorView創建聯繫?
  • 3.0.0.5 getWidth()方法和getMeasureWidth()區別呢?爲何有時候用getWidth()或者getMeasureWidth()獲得0?
  • 3.0.0.6 平時寫的自定義控件有哪些?如何優化自定義view?View的繪製流程說一下?自定義View的注意點?
  • 3.0.0.7 View的wrap_content和match_parent效果一致的緣由分析?getDefaultSize方法的處理邏輯?
  • 3.0.0.8 ViewGroup(抽象類)的measure流程?getChildMeasureSpec獲取子元素MeasureSpec的要點?
  • 3.0.0.9 View的layout過程?View的layout()源碼分析?LinearLayout的onLayout方法?View的測量寬高和最終寬高有什麼區別?
  • 3.0.1.0 draw的過程步驟是什麼?View特殊方法setWillNotDraw是幹什麼用的?
  • 3.0.1.1 View中x,y,translationX,translationY分別是什麼?View平移時是否改變了left、top等原始參數?
  • 3.0.1.2 MeasureSpec是什麼?MeasureSpec的組成?測量模式SpecMode的類型和具體含義?MeasureSpec和LayoutParams的對應關係?
  • 3.0.1.3 如何獲取View的測量寬/高?如何在Activity啓動時得到View的寬/高?Activity中得到View寬高的4種辦法?
  • 3.0.1.4 Activity啓動到最終加載ViewRoot(執行三大流程)的流程是什麼?
  • 3.0.1.5 自定義View性能優化有哪些?針對異常銷燬,自定義View如何優化?如何避免建立大量對象?

好消息

  • 博客筆記大彙總【15年10月到至今】,包括Java基礎及深刻知識點,Android技術博客,Python學習筆記等等,還包括平時開發中遇到的bug彙總,固然也在工做之餘收集了大量的面試題,長期更新維護而且修正,持續完善……開源的文件是markdown格式的!同時也開源了生活博客,從12年起,積累共計500篇[近100萬字],將會陸續發表到網上,轉載請註明出處,謝謝!
  • 連接地址:https://github.com/yangchong211/YCBlogs
  • 若是以爲好,能夠star一下,謝謝!固然也歡迎提出建議,萬事起於忽微,量變引發質變!全部的筆記將會更新到GitHub上,同時保持更新,歡迎同行提出或者push不一樣的見解或者筆記!

3.0.0.1 View的繪製須要通過哪些過程?有哪些經常使用回調方法?View的繪製流程的詳細流程是怎樣的?

  • View的繪製須要通過哪些過程?
    • measure:測量View的寬和高
      • View的measure方法是final類型方法——代表該方法沒法被重載
      • View的measure方法會調用onMeasure方法,onMeasure會調用setMeasuredDimension方法設置View寬/高的測量值
    • layout:肯定View在父控件中的放置位置
    • draw:負責將View繪製在屏幕上。技術博客大總結
  • 有哪些經常使用回調方法?
    • 構造方法
    • onAttachToWindow:在包含View的Activity啓動時調用
    • onDetachFromWindow:在包含View的Activity退出或者View被remove時回調
    • onVisibilityChanged:當View的可見狀態發生改變時調用
  • 比較重要的概念
    • ViewRoot:鏈接WindowManager(外界訪問Window的入口)和DecorView(頂級View)的紐帶,View的三大流程均是經過ViewRoot來完成的。
    • DecorView:頂級View
      • DecorView是頂級View,本質就是一個FrameLayout
      • 包含了兩個部分,標題欄和內容欄
      • 內容欄id是content,也就是activity中setContentView所設置的部分,最終將佈局添加到id爲content的FrameLayout中
  • View的繪製流程的詳細流程是怎樣的?技術博客大總結
    • View的繪製流程是從ViewRoot的PerformTraversals方法開始的。大概的流程以下所示
      • performTraversals會依次調用performMeasure, performLayout, performDraw三個方法,這三個方法分別完成頂層View的measure,layout,draw方法,onMeasure又會調用全部子元素的measure過程,直到完成整個View樹的遍歷。同理,performLayout, performDraw的傳遞流程與performMeasure類似。惟一不一樣在於,performDraw的傳遞過程在draw方法中經過dispatchDraw實現,但沒有本質區別。
      • Measure過程後能夠調用getMeasureWidth和getMeasureHeight方法獲取View測量後的寬高,與getWidth和getHeight的區別是:getMeasuredHeight()返回的是原始測量高度,與屏幕無關,getHeight()返回的是在屏幕上顯示的高度。實際上在當屏幕能夠包裹內容的時候,他們的值是相等的,只有當view超出屏幕後,才能看出他們的區別。當超出屏幕後,getMeasuredHeight()等於getHeight()加上屏幕以外沒有顯示的高度。
      • Layout過程肯定View四個頂點的位置和實際的寬高。
      • Draw過程肯定View的顯示,只有draw方法完成後View的內容纔會出如今屏幕上。
      • image

3.0.0.2 View繪製流程,當一個TextView的實例調用setText()方法後執行了什麼?請說一下原理……

  • View的繪製流程主要分爲三步:
    • onMeasure:測量視圖的大小,從頂層父View到子View遞歸調用measure()方法,measure()調用onMeasure()方法,onMeasure()方法完成繪製工做。
    • onLayout:肯定視圖的位置,從頂層父View到子View遞歸調用layout()方法,父View將上一步measure()方法獲得的子View的佈局大小和佈局參數,將子View放在合適的位置上。
    • onDraw:繪製最終的視圖,首先ViewRoot建立一個Canvas對象,而後調用onDraw()方法進行繪製。onDraw()方法的繪製流程爲
      • ① 繪製視圖背景。
      • ② 繪製畫布的圖層。 技術博客大總結
      • ③ 繪製View內容。
      • ④ 繪製子視圖,若是有的話。
      • ⑤ 還原圖層。
      • ⑥ 繪製滾動條。

3.0.0.3 requestLayout()、invalidate()與postInvalidate()有什麼區別?requestLayout()什麼時候不會觸發onDraw()?

  • invalidate() postInvalidate()
    • invalidate()該方法遞歸調用父View的invalidateChildInParent()方法,直到調用ViewRootImpl的invalidateChildInParent()方法,最終觸發ViewRootImpl的performTraversals()方法,此時mLayoutRequestede爲false,不會觸發onMesaure()與onLayout()方法,有可能會觸發onDraw()方法。
    • 共同點:都是調用onDraw()方法,而後去達到重繪view的目的
    • 區別:invalidate()用於主線程,postInvalidate()用於子線程
  • requestLayout()
    • 該方法會遞歸調用父窗口的requestLayout()方法,直到觸發ViewRootImpl的performTraversals()方法,此時mLayoutRequestede爲true,會觸發onMesaure()與onLayout()方法,不必定會觸發onDraw()方法。
    • 當view肯定自身已經再也不適合現有的區域時,該view自己調用這個方法要求parent view(父類的視圖)從新調用他的onMeasure、onLayout來從新設置本身位置。特別是當view的layoutparameter發生改變,而且它的值還沒能應用到view上時,這時候適合調用這個方法requestLayout()。requestLayout調用onMeasure和onLayout,不必定調用onDraw技術博客大總結
  • 如何選擇
    • 通常說來須要從新佈局就調用requestLayout()方法,須要從新繪製就調用invalidate()方法。
  • requestLayout()什麼時候不會觸發onDraw()?
    • 若是沒有改變控件的left\right\top\bottom就不會觸發onDraw()
  • invalidate()在什麼狀況下不會觸發onDraw?
    • 在ViewGroup中,invalidate默認不從新繪製子view。
  • 如何讓ViewGroup在invalidate時會觸發onDraw?技術博客大總結
    • 本質須要將ViewGroup的dirtyOpaque設置爲false
      • 1.在構造函數中調用setWillNotDraw(false);
      • 2.給ViewGroup設置背景。調用setBackground。

3.0.0.4 DecorView的做用是什麼?DecorView中如何獲取ContentView以及Activity所設置的View?ViewRootIml如何和DecorView創建聯繫?

  • DecorView的做用是什麼?
    • DecorView是頂級View,本質就是一個FrameLayout
    • 包含了兩個部分,標題欄和內容欄,內容欄id是content,也就是activity中setContentView所設置的部分,最終將佈局添加到id爲content的FrameLayout中技術博客大總結
  • DecorView中如何獲取ContentView以及Activity所設置的View?
    • 獲取content:ViewGroup content = findViewById(R.android.id.content)
    • 獲取設置的View:content.getChidlAt(0)
  • ViewRootIml如何和DecorView創建聯繫?技術博客大總結
    • Activity對象在ActivityThread中建立完畢後,會將DecorView添加到Window中
    • 同時會建立ViewRootImpl,調用ViewRoot的setView方法將ViewRootImpl和DevorView創建關聯
      root = new ViewRootImpl(view.getContext(), display);
      root.setView(view, wparams, panelParentView);
  • ViewRoot爲何要和DecorView創建關聯
    • DecorView等View的三大流程須要經過ViewRoot完成

3.0.0.5 getWidth()方法和getMeasureWidth()區別呢?爲何有時候用getWidth()或者getMeasureWidth()獲得0?

  • getWidth()方法和getMeasureWidth()區別呢
    • getMeasureWidth()
      • getMeasureWidth()方法在measure()過程結束後就能夠獲取到了,另外,getMeasureWidth()方法中的值是經過setMeasuredDimension()方法來進行設置的
      • 這裏mMeasuredWidth & MEASURED_SIZE_MASK表示的是測量階段結束以後,view真實的值。
      public final int getMeasuredWidth() {
          return mMeasuredWidth & MEASURED_SIZE_MASK;
      }
    • getWidth()
      • getWidth()方法要在layout()過程結束後才能獲取到,getWidth()方法中的值則是經過視圖右邊的座標減去左邊的座標計算出來的。
      • mRight和mLeft是什麼值,是在何時被設置的。具體看layout()過程當中源碼
      @ViewDebug.ExportedProperty(category = "layout")
      public final int getWidth() {
          return mRight - mLeft;
      }
  • 爲何有時候用getWidth()或者getMeasureWidth()獲得0
    • 問題描述:使用getMeasuredWidth()和getMeasuredHeight()方法,不管是在onCreate()、onStart()、onResume()中調用,都沒法獲得控件的長度、和寬度。以下圖,測量的結果爲0。
    • 解釋:技術博客大總結
      • 由於View的Measure過程和Activity的生命週期方法不是同步執行的,因此沒法保證Activity執行了onCreate()、onStart()、onResume()時某個View已經測量完畢了,若是View尚未測量完畢,那麼得到寬/高就是0。
      • 後來以爲這種解釋有點牽強,好比
  • 解決控件測量寬高問題
    • 以下所示
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        test();
    }
    
    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        getWidth(4);
    }
    
    private void test(){
        getWidth(1);
    
        marqueeView.measure(0, 0);
        getWidth(2);
    
        marqueeView.post(new Runnable() {
            @Override
            public void run() {
                getWidth(3);
            }
        });
    }
    
    private void getWidth(int a){
        int width2 = marqueeView.getWidth();
        int measuredWidth2 = marqueeView.getMeasuredWidth();
        Log.e(a+"MainActivity-----",width2+"-----"+measuredWidth2);
    }
    
    //11-28 17:03:17.559 15990-15990/com.yc.cn.ycbanner E/1MainActivity-----: 0-----0
    //11-28 17:03:17.567 15990-15990/com.yc.cn.ycbanner E/2MainActivity-----: 0-----760
    //11-28 17:03:17.684 15990-15990/com.yc.cn.ycbanner E/3MainActivity-----: 960-----960
    //11-28 17:03:17.685 15990-15990/com.yc.cn.ycbanner E/4MainActivity-----: 960-----960
  • 何時測量寬高不等於實際寬高?
    • MeasuredWidth/height!=getWidth/Height()的場景:更改View的佈局參數並進行從新佈局後,就會致使測量寬高!=實際寬高

3.0.0.6 平時寫的自定義控件有哪些?如何優化自定義view?View的繪製流程說一下?自定義View的注意點?

  • 平時寫的自定義控件有哪些?
    • 1組合控件。這種自定義控件不須要咱們本身繪製,而是使用原生控件組合成的新控件。如標題欄,recyclerView封裝控件。
    • 2繼承原有的控件。這種自定義控件在原生控件提供的方法外,能夠本身添加一些方法。好比圖片縮放控件,進度條控件。
    • 3徹底自定義控件:這個View上所展示的內容所有都是咱們本身繪製出來的。好比百分比進度條控件
  • 如何優化自定義 view
    • 爲了加速你的view,對於頻繁調用的方法,須要儘可能減小沒必要要的代碼。先從onDraw開始,須要特別注意不該該在這裏作內存分配的事情,由於它會致使GC,從而致使卡頓。在初始化或者動畫間隙期間作分配內存的動做。不要在動畫正在執行的時候作內存分配的事情。
    • 你還須要儘量的減小onDraw被調用的次數,大多數時候致使onDraw都是由於調用了invalidate().所以請儘可能減小調用invaildate()的次數。若是可能的話,儘可能調用含有4個參數的invalidate()方法而不是沒有參數的invalidate()。沒有參數的invalidate會強制重繪整個view。技術博客大總結
    • 另一個很是耗時的操做是請求layout。任什麼時候候執行requestLayout(),會使得Android UI系統去遍歷整個View的層級來計算出每個view的大小。若是找到有衝突的值,它會須要從新計算好幾回。另外須要儘可能保持View的層級是扁平化的,這樣對提升效率頗有幫助。
    • 若是你有一個複雜的UI,你應該考慮寫一個自定義的ViewGroup來執行他的layout操做。與內置的view不一樣,自定義的view可使得程序僅僅測量這一部分,這避免了遍歷整個view的層級結構來計算大小。這個PieChart 例子展現瞭如何繼承ViewGroup做爲自定義view的一部分。PieChart 有子views,可是它歷來不測量它們。而是根據他自身的layout法則,直接設置它們的大小。
  • View的繪製流程說一下?
    • View的繪製流程:OnMeasure()——>OnLayout()——>OnDraw()
    • 第一步:OnMeasure():測量視圖大小。從頂層父View到子View遞歸調用measure方法,measure方法又回調OnMeasure。
    • 第二步:OnLayout():肯定View位置,進行頁面佈局。從頂層父View向子View的遞歸調用view.layout方法的過程,即父View根據上一步measure子View所獲得的佈局大小和佈局參數,將子View放在合適的位置上。
    • 第三步:OnDraw():繪製視圖。ViewRoot建立一個Canvas對象,而後調用OnDraw()。六個步驟:①、繪製視圖的背景;②、保存畫布的圖層(Layer);③、繪製View的內容;④、繪製View子視圖,若是沒有就不用;⑤、還原圖層(Layer);⑥、繪製滾動條。技術博客大總結
  • 自定義View的注意點?
    • View須要支持wrap_content、padding
    • ViewGroup須要支持子View的margin和自身的padding
    • 儘可能不要在View中使用Handler,View已經有post系列方法
    • View若是有線程或者動畫,須要及時中止(onDetachedFromWindow會在View被remove時調用)——避免內存泄露
    • View若是有滑動嵌套情形,須要處理好滑動衝突

3.0.0.7 View的wrap_content和match_parent效果一致的緣由分析?getDefaultSize方法的處理邏輯?

  • View的wrap_content和match_parent效果一致的緣由分析?
    • 根據View的onMeasure方法中的getDefaultSize方法,咱們能夠發如今兩種模式下,View的測量值等於該View的測量規格MeasureSpec中的尺寸。
    • View的MeasureSpec本質是由自身的LayoutParams和父容器的MeasureSpec決定的。
    • 當View爲wrap_content時,該View的模式爲AT_MOST,且尺寸specSize爲父容器的剩餘空間大小。
    • 當View爲match_parent時,該View的模式跟隨父容器的模式(AT_MOST/EXACTLY), 且尺寸specSize爲父容器的剩餘空間大小。
    • 所以getDefaultSize中不管View是哪一種模式,最終測量寬/高均等於尺寸specSize,所以兩種屬性效果是徹底同樣的(View的大小充滿了父容器的剩餘空間)技術博客大總結
    • 除非給定View固定的寬/高,View的specSize纔會等於該固定值。
  • getDefaultSize方法的處理邏輯?
    • getDefaultSize: 根據建議獲取的最小寬高和測量規格,決定實際的測量寬高
      • UNSPECIFIED模式:測量寬高 = 建議的最小寬高
      • EXACTLY / AT_MOST模式:測量寬高 = specSize技術博客大總結
    • View的getDefaultSize源碼要點(決定了View寬高的測量值)
      • UNSPECIFIED模式時,寬/高爲第一個參數也就是getSuggestedMinimumWidth()獲取的建議最小值
      • AT_MOST(wrap_content)和EXACTLY(match_parent/具體值dp等)這兩個模式下,View寬高的測量值爲當前View的MeasureSpec(測量規格)中指定的尺寸specsize

3.0.0.8 ViewGroup(抽象類)的measure流程?getChildMeasureSpec獲取子元素MeasureSpec的要點?

  • ViewGroup(抽象類)的measure流程?
    • ViewGroup沒有onMeasure方法,只定義了measureChildren方法(onMeasure根據不一樣佈局難以統一)
    • measureChildren中遍歷全部子元素並調用measureChild方法
    • measureChild方法中會獲取子View的MeasureSpec(getChildMeasureSpec),而後調用子元素View的measure方法進行測量
  • getChildMeasureSpec獲取子元素MeasureSpec的要點?
    • 子View的MeasureSpec是根據自身的LayoutParams和父容器SpecMode生成
    • 當子View的佈局參數爲wrap_content,且父容器模式爲AT_MOST時,效果與子元素佈局爲match_parent是同樣的。所以當子View的佈局參數爲wrap_content時,須要給指定默認的寬/高
  • LinearLayout的onMeasure()分析
    • ViewGroup由於佈局的不一樣,沒法統一onMeasure方法,具體內容根據佈局的不一樣而不一樣,這裏直接以LinearLayout進行分析
    • onMeasure會根據orientation選擇measureVertical或者measureHorizontal進行測量
    • measureVertical本質是遍歷子元素,並執行子元素的measure方法,並得到子元素的總高度以及子元素在豎直方向上的margin等。技術博客大總結
    • 最終LinearLayout會測量本身的大小,在orientation的方向上,若是佈局是match_parent或者具體數值,測量過程與View一致(高度爲specSize);若是佈局是wrap_content,高度是全部子元素高度總和,且不會超過父容器的剩餘空間,最終高度須要考慮在豎直方向上的padding

3.0.0.9 View的layout過程?View的layout()源碼分析?LinearLayout的onLayout方法?View的測量寬高和最終寬高有什麼區別?

  • View的layout過程?
    • 使用layout方法肯定View自己的位置
    • layout中調用onLayout方法肯定全部子View的位置
  • View的layout()源碼分析?
    • 調用setFrame()設置View四個定點位置(即初始化mLeft,mRight,mTop,mBottom的值)
    • 以後調用onLayout肯定子View位置,該方法相似於onMeasure,View和ViewGroup中均沒有實現,具體實現與具體佈局有關。
  • LinearLayout的onLayout方法?
    • 根據orientation選擇調用layoutVertical或者layoutHorizontal
    • layoutVertical中會遍歷全部子元素並調用setChildFrame(裏面直接調用子元素的layout方法)
    • 層層傳遞下去完成了整個View樹的layout過程
    • setChildFrame中的寬/高實際就是子元素的測量寬/高(getMeasure…後直接傳入)
  • View的測量寬高和最終寬高有什麼區別?技術博客大總結
    • 等價於getMeasuredWidth和getWidth有什麼區別
    • getWidth = mRight - mLeft,結合源碼測量值和最終值是徹底相等的。
    • 區別在於:測量寬高造成於measure過程,最終寬高造成於layout過程(賦值時機不一樣)
    • 也有可能致使二者不一致:強行重寫View的layout方法,在傳參方面改變最終寬/高(雖然這樣毫無實際意義)
    • 某些狀況下,View須要屢次measure才能肯定本身的測量寬高,在前幾回測量中等到的值可能有最終寬高不一致。可是最終結果上,測量寬高=最終寬高

3.0.1.0 draw的過程步驟是什麼?View特殊方法setWillNotDraw是幹什麼用的?

  • draw的過程步驟是什麼?
    • 繪製背景(drawBackground(canvas))
    • 繪製本身(onDraw)
    • 繪製children(dispatchDraw)-遍歷調用全部子View的draw方法
    • 繪製裝飾(如onDrawScollBars)
  • View特殊方法setWillNotDraw是幹什麼用的?
    • 若一個View不繪製任何內容,須要將該標誌置爲true,系統會進行相應優化
    • 默認View不開啓該標誌位技術博客大總結
    • 默認ViewGroup開啓該標誌位
    • 若是咱們自定義控件繼承自ViewGroup而且自己不進行繪製時,就能夠開啓該標誌位
    • 當該ViewGroup明確經過onDraw繪製內容時,就須要顯式關閉WILL_NOT_DRAW標誌位。

3.0.1.1 View中x,y,translationX,translationY分別是什麼?View平移時是否改變了left、top等原始參數?

  • View中x,y,translationX,translationY分別是什麼?
    • x,y是View當前左上角的座標
    • translationX,translationY是在滑動/動畫後,View當前位置和View最原始位置的距離。
    • 所以得出等式:x(View左上角當前位置) = left(View左上角初始位置) + translationX(View左上角偏移的距離)
  • View平移時是否改變了left、top等原始參數?技術博客大總結
    • View平移時top、left等參數不變,改變的是x,y,tranlsationX和tranlsationY

3.0.1.2 MeasureSpec是什麼?MeasureSpec的組成?測量模式SpecMode的類型和具體含義?MeasureSpec和LayoutParams的對應關係?

  • MeasureSpec是什麼?
    • MeasureSpec是一種「測量規則」或者「測量說明書」,決定了View的測量過程
    • View的MeasureSpec會根據自身的LayoutParamse和父容器的MeasureSpec生成。
    • 最終根據View的MeasureSpec測量出View的寬/高(測量時數據並不是最終寬高)
  • MeasureSpec的組成?
    • MeasureSpec表明一個32位int值,高2位是SpecMode,低30位是SpecSize
    • SpecMode是指測量模式
    • SpecSize是指在某種測量模式下的大小
    • 類MesaureSpec提供了用於SpecMode和SpecSize打包和解包的方法
  • 測量模式SpecMode的類型和具體含義?技術博客大總結
    • UNSPECIFIED:父容器不對View有任何限制,通常用於系統內部
    • EXACTLY:精準模式,View的最終大小就是SpecSize指定的值(對應於LayoutParams的match_parent和具體的數值)
    • AT_MOST:最大值模式,大小不能大於父容器指定的值SpecSize(對應於wrap_content)
  • MeasureSpec和LayoutParams的對應關係?
    • View的MeasureSpec是須要經過自身的LayoutParams和父容器的MeasureSpec一塊兒才能決定
    • DecorView(頂級View)是例外,其自己MeasureSpec由窗口尺寸和自身LayoutParams共同決定
    • MeasureSpec一旦肯定,onMeasure中就能夠肯定View的測量寬/高

3.0.1.3 如何獲取View的測量寬/高?如何在Activity啓動時得到View的寬/高?Activity中得到View寬高的4種辦法?

  • 如何獲取View的測量寬/高?
    • 在measure完成後,能夠經過getMeasuredWidth/Height()方法,就能得到View的測量寬高
    • 在必定極端狀況下,系統須要屢次measure,所以獲得的值可能不許確,最好的辦法是在onLayout方法中得到測量寬/高或者最終寬/高
  • 如何在Activity啓動時得到View的寬/高?
    • Activity的生命週期與View的measure不是同步運行,所以在onCreate/onStart/onResume均沒法正確獲得
    • 若在View沒有測量好時,去得到寬高,會致使最終結果爲0
    • 有四種辦法去正確得到寬高
  • Activity中得到View寬高的4種辦法?技術博客大總結
    • onWindowFocusChanged
      • View已經初始化完畢,能夠得到寬高;Activity獲得焦點和失去焦點均會調用一次(頻繁onResume和onPause會致使頻繁調用)
    • view.post(runnable)
      • 經過post將一個runnable投遞到消息隊列尾部;等到Looper調用次runnable時,View已經完成初始化
    • ViewTreeObserver
      • 使用ViewTreeObserver的接口,能夠在View樹狀態改變或者View樹內部View的可見性改變時,onGlobalLayout會被回調;能正確獲取View寬/高
    • view.measure

3.0.1.4 Activity啓動到最終加載ViewRoot(執行三大流程)的流程是什麼?

  • Activity啓動到最終加載ViewRoot(執行三大流程)的流程是什麼?
    • Activity調用startActivity方法,最終會調用ActivityThread的handleLaunchActivity方法
    • handleLaunchActivity會調用performLauchActivity方法(會調用Activity的onCreate,並完成DecorView的建立)和handleResumeActivity方法
    • handleResumeActivity方法會作四件事:performResumeActivity(調用activity的onResume方法)、getDecorView(獲取DecorView)、getWindowManager(獲取WindowManager)、WindowManager.addView(decor, 1)
    • WindowManager.addView(decor, 1)本質是調用WindowManagerGlobal的addView方法。其中主要作兩件事:一、建立ViewRootImpl實例 二、root.setView(decor, ….)將DecorView做爲參數添加到ViewRoot中,這樣就將DecorView加載到了Window中
    • ViewRootImpl還有一個方法performTraveals方法,用於讓ViewTree開始View的工做流程:其中會調用performMeasure/Layout/Draw()三個方法,分別對應於View的三大流程。

3.0.1.5 自定義View性能優化有哪些?針對異常銷燬,自定義View如何優化?如何避免建立大量對象?

  • 自定義View性能優化有哪些?
    • 避免過分繪製
    • 儘可能減小或簡化計算
    • 避免建立大量對象形成頻繁GC
    • 禁止或避免I/O操做
    • onDraw中避免冗餘代碼、避免建立對象
    • 複合View,要減小布局層級。
    • 狀態和恢復和保存
    • 開啓硬件加速
    • 合理使用invalidate的參數版本。
    • 減小冗餘代碼:不要使用Handler,由於已經有post系列方法.
    • 使用的線程和動畫,要在onDetachedFromWindow中進行清理工做。
    • 要妥善處理滑動衝突。
  • 避免過分繪製
    • 像素點能畫一次就不要屢次繪製,以及繪製看不到的背景
    • 開發者選項裏內的工具,只對xml佈局有效果,看不到自定義View的過分繪製,仍然須要注意。
  • 儘可能減小或簡化計算
    • 不要作無用計算。儘量的複用計算結果。技術博客大總結
    • 沒有數據,或者數據較少的時候應如何處理,沒有事件須要響應的時候如何處理。
    • 應該避免在for或while循環中作計算。好比:去計算屏幕寬度等信息。
  • 避免建立大量對象形成頻繁GC
    • 應該避免在for或while循環中new對象。這是減小內存佔用量的有效方法。
  • 禁止或避免I/O操做
    • I/O操做對性能損耗極大,不要在自定義View中作IO操做。
  • onDraw中避免冗餘代碼、避免建立對象
    • onDraw中禁止new對象.如:不該該在ondraw中建立Paint對象。Paint類提供了reset方法。能夠在初始化View時建立對象。
    • 要避免冗餘代碼,提升效率。
  • 複合View,要減小布局層級。
    • 複合控件:繼承自現有的LinearLayout等ViewGroup,而後組合多個控件來實現效果。這種實現方法要注意減小布局層級,層級越高性能越差。
  • 狀態和恢復和保存
    • Activity還會由於內存不足或者旋轉屏幕而致使重建Activity,自定義View也要去進行自我狀態的保存和讀取。
    • 在onSaveInstanceState()保存狀態;在onRestoreInstanceState()恢復狀態
  • 開啓硬件加速
  • 合理使用invalidate的參數版本。技術博客大總結
    • 避免任何請款下之際調用默認參數的invalidate
    • 調用有參數的invalidate進行局部和子View刷新,可以提升性能。
  • 減小冗餘代碼:不要使用Handler,由於已經有post系列方法
    • View已經有post系列方法,沒有必要重複去寫。
    • 能夠直接使用,最終會投遞到主線程的Handler中
  • 使用的線程和動畫,要在onDetachedFromWindow中進行清理工做。
    • View若是有線程或者動畫,須要及時中止.
    • View的onDetachedFromWindow會在View被remove時調用,在該方法內進行終止
    • 這樣能避免內存泄露
  • 要妥善處理滑動衝突。
    • View若是有滑動嵌套情形,須要處理好滑動衝突

關於其餘內容介紹

01.關於博客彙總連接

02.關於個人博客

相關文章
相關標籤/搜索