日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

?1.車系頁布局渲染現狀 

 

車系頁是重要的車系信息頁面,更新迭代多年,頁面布局不斷變化,xml布局文件越寫越復雜。

獲取車系頁布局文件耗時:

startTime = System.currentTimeMillis();
        setContentView(R.layout.car_series_revision_activity);
        long durTime = System.currentTimeMillis() - startTime;
        LogHelper.e("布局總耗時","車系頁布局耗時:" + durTime);

結果如下:

 

圖片

 

 

 

2.卡頓的原因

 

2.1Android繪制原理

? 1.Android的屏幕刷新中涉及到最重要的三個概念

(1)CPU:執行應用層的measure、layout、draw等操作,繪制完成后將數據提交給GPU

(2)GPU:進一步處理數據,并將數據緩存起來

(3)屏幕:由一個個像素點組成,以固定的頻率(16.6ms,即1秒60幀)從緩沖區中取出數據來填充像素點

總結一句話就是:CPU 繪制后提交數據、GPU 進一步處理和緩存數據、最后屏幕從緩沖區中讀取數據并顯示。

圖片

? 2.雙緩沖機制

圖片

當布局比較復雜,或設備性能較差的時候,CPU并不能保證在16.6ms內就完成繪制數據的計算,所以這里系統又做了一個處理。

當你的應用正在往Back Buffer中填充數據時,系統會將Back Buffer鎖定。

如果到了GPU交換兩個Buffer的時間點,你的應用還在往Back Buffer中填充數據,GPU會發現Back Buffer被鎖定了,它會放棄這次交換。

這樣做的后果就是手機屏幕仍然顯示原先的圖像,這就是我們常常說的掉幀。

2.2布局加載原理

頁面啟動時,布局加載在主線程上進行耗時操作,會導致頁面渲染及加載慢。

布局加載主要通過setContentView來實現,下面是它的調用時序圖:

圖片

我們可以看到,在setContentView中主要有兩個耗時操作:

(1)解析xml,獲取XmlResourceParser,這是IO過程。

(2)通過createViewFromTag,創建View對象,用到了反射。

以上兩點就是布局加載慢的原因,也是布局的性能瓶頸。

 

 

3.布局加載優化

 

上一章分析了布局加載慢的主要原因,因此,我們的優化方式主要有以下兩種:

(1)異步加載,將布局加載過程轉移到子線程

(2)去掉IO和反射過程

3.1異步加載,AsyncLayoutInflater方案

 setContentView 默認是在UI主線程加載布局的,其加載過程中的耗時操作,如解析xml,反射創建view對象等也是在主線程執行,AsyncLayoutInflater 可以讓這些加載過程在子線程中執行,這樣可以提高UI線程的響應性,UI線程同時可以進行其他操作。AsyncLayoutInflater使用方式如下:

new AsyncLayoutInflater(this).inflate(R.layout.car_series_revision_activity, null, new AsyncLayoutInflater.OnInflateFinishedListener() {
            @Override
            public void onInflateFinished(@NonNull View view, int resid, @Nullable ViewGroup parent) {
                setContentView(view);
            }
        });

AsyncLayoutInflater方案的缺點:

(1) UI布局和view的初始化在子線程中進行,如果view還未初始化成功,在主線程中再調用view會引起崩潰。

(2) 一般情況下,主線程會調用view,涉及到大量子線程和主線程在view調用上的同步問題,這就犧牲了易用性,代碼可維護性也會變差。

(3) 如果是在老頁面邏輯結構上引入AsyncLayoutInflater進行改造,結構改動很大,很容易發生view調用崩潰錯誤,不太可行。

3.2X2C方案

 X2C 是掌閱開源的一套布局加載框架。X2C的主要思路是利用apt工具,在編譯期將我們寫的xml布局文件解析成view,并根據xml動態設置view的各類屬性,這樣,我們在運行時,調用findViewById,根據view id拿到的view,已經是直接new 出來的view,避免了運行時的xml IO操作和反射操作,這就解決了布局時的耗時問題。

原始的xml布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:App="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/constraintLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientatinotallow="vertical">
    <Button
        android:id="@+id/x2c"
        style="@style/btn"
        android:text="X2C" />
    <Button
        android:id="@+id/xml"
        style="@style/btn"
        android:layout_marginTop="10dp"
        android:text="XML" />
    <Button
        android:id="@+id/sub"
        style="@style/btn"
        android:layout_marginTop="10dp"
        android:text="subModule" />
</LinearLayout>

X2C 編譯期apt生成的JAVA文件:

public class X2C127_Activity implements IViewCreator {
  @Override
  public View createView(Context ctx) {
     Resources res = ctx.getResources();
        LinearLayout linearLayout0 = new LinearLayout(ctx);
        linearLayout0.setTag(R.id.x2c_rootview_width,ViewGroup.LayoutParams.MATCH_PARENT);
        linearLayout0.setTag(R.id.x2c_rootview_height,ViewGroup.LayoutParams.MATCH_PARENT);
        linearLayout0.setId(R.id.constraintLayout);
        linearLayout0.setGravity(Gravity.CENTER);
        linearLayout0.setOrientation(LinearLayout.VERTICAL);
        Button button1 = new Button(ctx);
        LinearLayout.LayoutParams layoutParam1 = new LinearLayout.LayoutParams((int)(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,150,res.getDisplayMetrics())),(int)(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,50,res.getDisplayMetrics())));
        button1.setBackgroundColor(res.getColor(R.color.colorAccent));
        button1.setTextSize(TypedValue.COMPLEX_UNIT_DIP,20);
        button1.setGravity(Gravity.CENTER);
        button1.setTextColor(Color.parseColor("#ffffff"));
        button1.setId(R.id.x2c);
        button1.setText("X2C");
        button1.setLayoutParams(layoutParam1);
        linearLayout0.addView(button1);
        return linearLayout0;
  }
}

X2c的優點:?

(1)易用性和可維護性好,對原有代碼侵入性不強,應用代碼還是使用xml寫布局

(2)加載耗時可縮短到原來的1/2到1/3

X2c的缺點:?

(1)View的屬性支持不完全

(2)兼容性和穩定性不是很高,在高版本的gradle 編譯工具,如gradle3.1.4,會出現找不到R.java文件,找不到xml對應的java文件等問題

(3)目前,X2C更新到2021年,并沒有持續維護和解決issue

3.3Compose方案

Compose 是 Jetpack 中的一個新成員,是 Android 團隊在2019年I/O大會上公布的新的UI庫。

Compose使用純kotlin開發,使用簡潔方便,但它是完全拋棄了View 和 ViewGroup這套系統,自己把整個的渲染機制從里到外做了個全新的,是未來取代XML的官方方案。

Compose的優點:

(1)使用聲明式UI,摒棄了xml布局運行時解析,布局效率更高

(2)使用kotlin開發,簡單易用,布局形式上跟flutter統一。

如果是使用kotlin開發的新項目,可以引入Compose方案,對于老項目的優化,Compose方案并不適用。

3.4我們的優化方案-在布局反射上做文章

 Xml解析到view,完全自己來做,比較復雜且有很多風險,這個過程涉及到兩個耗時的點:

(1)xml解析,IO操作

(2)反射

xml解析這部分工作復雜度很高,可以交給android系統來做。我們可以想辦法去除反射的邏輯。

我們需要找到一個反射生成view的入口。我們知道,View生成相關邏輯在LayoutInflater的createViewFromTag中,調用了onCreateView(parent, name, context, attrs),通過反射生成了view。

通過android系統的LayoutInflater setFactory,我們不僅可以控制View的生成,還可以把View變成另外一個View。在setFactory的onCreateView(parent, name, context, attrs)回調中,我們接管單個view的生成,去掉反射,new 出我們自己的view就解決了問題。而onCreateView(parent, name, context, attrs)中的參數name返回的就是xml中使用到的view的名字,根據這個name,直接new出來新的view。方式如下:

LayoutInflaterCompat.setFactory(getLayoutInflater(), new LayoutInflaterFactory() {
            @Override
            public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
                switch (name) {
                    case "TextView":
                        return new TextView(context, attrs);
                    case "ImageView":
                        return new ImageView(context, attrs);
                    case "com.cubic.choosecar.ui.car.view.NewStarView":
                        return new com.cubic.choosecar.ui.car.view.NewStarView(context, attrs);
                    case "com.cubic.choosecar.ui.carseries.scrolllayout.ScrollableLayout":
                        return new com.cubic.choosecar.ui.carseries.scrolllayout.ScrollableLayout(context, attrs);
                    case "View":
                        return new View(context, attrs);
                    case "com.cubic.choosecar.newui.carseries.view.CarRevisionSeriesImageScaleLayout": //自定義view
                        return new com.cubic.choosecar.newui.carseries.view.CarRevisionSeriesImageScaleLayout(context, attrs);
                    case "ViewStub":
                        return new ViewStub(context, attrs);
                    case "ScrollView":
                        return new ScrollView(context, attrs);
                    case "androidx.constraintlayout.widget.ConstraintLayout":
                        return new androidx.constraintlayout.widget.ConstraintLayout(context, attrs);
                    case "FrameLayout":
                        return new FrameLayout(context, attrs);
                    case "RelativeLayout":
                        return new RelativeLayout(context, attrs);
                    case "androidx.appcompat.widget.Toolbar":
                        return new androidx.appcompat.widget.Toolbar(context, attrs);
                    case "LinearLayout":
                        return new LinearLayout(context, attrs);
                    default:
                        View view = getDelegate().createView(parent, name, context, attrs);
                        return view;
                }
                //return view;
            }
        });
 

包括系統view和我們自定義的view。

此方案對已有項目的代碼侵入性很小,改造成本低,兼容性也很高,相對來講,在渲染效率上比X2C方案低一些,但比較匹配我們對已有舊項目復雜布局的渲染優化。

 

3.5進一步在布局上優化

 我們可以使用viewStub實現布局的懶加載。思路是將布局分成不同的模塊,讓部分模塊使用viewStub標簽替代,一半屏幕的模塊元素渲染完成以后,再通過viewStub來渲染生成viewStub所包含的其它模塊,實現延遲渲染加載。

通過分析車系頁布局,已經將布局元素,按功能做了一些模塊的劃分,我們進一步將關聯度大的布局模塊集中在一起,封裝在一個自定義VIEW中,使用viewStub包含替換這些模塊View。UI線程setContentView渲染布局時,viewStub所包含的模塊并不會被渲染,只會渲染屏幕的部分元素,等待主接口數據返回,再使用viewStub延遲其它模塊,實現了布局的懶加載,加快了主線程的渲染速度。

 

 

4.優化結果

 

通過3.4和3.5節的優化方法,車系頁復雜布局渲染優化對比結果如下:

圖片

通過對比可以看到,在不同檔次的android機型上,渲染耗時降低了20%-35%左右,在低端機型上,減少的絕對耗時更多,感受可能會明顯一些。

 

 

 

作者簡介

圖片

 

蔣雄鋒

■ 經銷商事業部-經銷商技術部。

■ 2018年加入汽車之間,目前任職經銷商技術部移動App團隊,主要涉及Android移動端,Flutter,React Native等大前端技術,負責汽車報價App業務的開發。

分享到:
標簽:Android
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定