Android 優(yōu)化自定義View

2018-08-02 18:13 更新

編寫:kesenhoo - 原文:http://developer.android.com/training/custom-views/optimizing-view.html

前面的課程學習到了如何創(chuàng)建設(shè)計良好的View,并且能夠使之在手勢與狀態(tài)切換時得到正確的反饋。下面要介紹的是如何使得view能夠執(zhí)行更快。為了避免UI顯得卡頓,你必須確保動畫能夠保持在60fps。

Do Less, Less Frequently

為了加速你的view,對于頻繁調(diào)用的方法,需要盡量減少不必要的代碼。先從onDraw開始,需要特別注意不應(yīng)該在這里做內(nèi)存分配的事情,因為它會導致GC,從而導致卡頓。在初始化或者動畫間隙期間做分配內(nèi)存的動作。不要在動畫正在執(zhí)行的時候做內(nèi)存分配的事情。

你還需要盡可能的減少onDraw被調(diào)用的次數(shù),大多數(shù)時候?qū)е耾nDraw都是因為調(diào)用了invalidate().因此請盡量減少調(diào)用invaildate()的次數(shù)。如果可能的話,盡量調(diào)用含有4個參數(shù)的invalidate()方法而不是沒有參數(shù)的invalidate()。沒有參數(shù)的invalidate會強制重繪整個view。

另外一個非常耗時的操作是請求layout。任何時候執(zhí)行requestLayout(),會使得Android UI系統(tǒng)去遍歷整個View的層級來計算出每一個view的大小。如果找到有沖突的值,它會需要重新計算好幾次。另外需要盡量保持View的層級是扁平化的,這樣對提高效率很有幫助。

如果你有一個復雜的UI,你應(yīng)該考慮寫一個自定義的ViewGroup來執(zhí)行他的layout操作。與內(nèi)置的view不同,自定義的view可以使得程序僅僅測量這一部分,這避免了遍歷整個view的層級結(jié)構(gòu)來計算大小。這個PieChart 例子展示了如何繼承ViewGroup作為自定義view的一部分。PieChart 有子views,但是它從來不測量它們。而是根據(jù)他自身的layout法則,直接設(shè)置它們的大小。

使用硬件加速

從Android 3.0開始,Android的2D圖像系統(tǒng)可以通過GPU (Graphics Processing Unit))來加速。GPU硬件加速可以提高許多程序的性能。但是這并不是說它適合所有的程序。Android framework讓你能過隨意控制你的程序的各個部分是否啟用硬件加速。

參考 Android Developers Guide 中的Hardware Acceleration 來學習如何在application, activity, 或 window 層啟用加速。注意除了 Android Guide 的指導之外,你必須要設(shè)置你的應(yīng)用的target API為11,或更高,通過在你的AndroidManifest.xml 文件中增加 < uses-sdk android:targetSdkVersion="11"/> 。

一旦你開啟了硬件加速,性能的提示并不一定可以明顯察覺到。移動設(shè)備的GPU在某些例如scaling,rotating與translating的操作中表現(xiàn)良好。但是對其他一些任務(wù),比如畫直線或曲線,則表現(xiàn)不佳。為了充分發(fā)揮GPU加速,你應(yīng)該最大化GPU擅長的操作的數(shù)量,最小化GPU不擅長操作的數(shù)量。

在下面的例子中,繪制pie是相對來說比較費時的。解決方案是把pie放到一個子view中,并設(shè)置View使用LAYER_TYPE_HARDWARE來進行加速。

private class PieView extends View {

       public PieView(Context context) {
           super(context);
           if (!isInEditMode()) {
               setLayerType(View.LAYER_TYPE_HARDWARE, null);
           }
       }

       @Override
       protected void onDraw(Canvas canvas) {
           super.onDraw(canvas);

           for (Item it : mData) {
               mPiePaint.setShader(it.mShader);
               canvas.drawArc(mBounds,
                       360 - it.mEndAngle,
                       it.mEndAngle - it.mStartAngle,
                       true, mPiePaint);
           }
       }

       @Override
       protected void onSizeChanged(int w, int h, int oldw, int oldh) {
           mBounds = new RectF(0, 0, w, h);
       }

       RectF mBounds;
   }

通過這樣的修改以后,PieChart.PieView.onDraw()只會在第一次現(xiàn)實的時候被調(diào)用。之后,pie chart會被緩存為一張圖片,并通過GPU來進行重畫不同的角度。GPU特別擅長這類的事情,并且表現(xiàn)效果突出。

緩存圖片到hardware layer會消耗video memory,而video memory又是有限的。基于這樣的考慮,僅僅在用戶觸發(fā)scrolling的時候使用LAYER_TYPE_HARDWARE,在其他時候,使用LAYER_TYPE_NONE。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號