Android X2C框架-提升布局加載速度200%

背景

一般大家在寫頁面時都是通過xml寫布局,通過setContentView、或LayoutInflater.from(context).inflate方法將xml布局加載到內(nèi)存中。

優(yōu)點(diǎn)

  • 可維護(hù)性好
  • 支持即時預(yù)覽
  • 代碼結(jié)構(gòu)清晰

缺點(diǎn)

  • 讀取xml很耗時
  • 遞歸解析xml較耗時
  • 反射生成對象的耗時是new的3倍以上

我們團(tuán)隊(duì)在這個問題上也探索過很多解決方案,一度走到了另一個極端,完全廢棄xml,所有控件通過java來new,甚至直接在canvas里繪制,這樣雖然性能確實(shí)提升了,但是代碼已經(jīng)沒有了一丁點(diǎn)可讀性,可維護(hù)性。 ????我們后來反思代碼到底是給機(jī)器看的,還是給人看的??也許X2C已經(jīng)給了我們一個答案

X2C

為了即保留xml的優(yōu)點(diǎn),又解決它帶來的性能問題,我們開發(fā)了X2C方案。即在編譯生成APK期間,將需要翻譯的layout翻譯生成對應(yīng)的java文件,這樣對于開發(fā)人員來說寫布局還是寫原來的xml,但對于程序來說,運(yùn)行時加載的是對應(yīng)的java文件。 ????我們采用APT(Annotation Processor Tool)+ JavaPoet技術(shù)來完成編譯期間【注解】->【解注解】->【翻譯xml】->【生成java】整個流程的操作。

性能對比

在開發(fā)集成完之后我們做了簡單的測試,性能對比如下

加載方式 次數(shù) 平均加載時間
XML 100 30
X2C 100 11

集成使用

1.導(dǎo)入依賴

在module的build.gradle文件添加依賴

annotationProcessor 'com.zhangyue.we:x2c-apt:1.1.2'
implementation 'com.zhangyue.we:x2c-lib:1.0.6'

2.添加注解

在使用布局的任意java類或方法添加注解即可

@Xml(layouts = "activity_main")

3.配置自定義屬性(沒有可不配)

在module下建立X2C_CONFIG.xml文件,里面配置定義屬性和方法的映射關(guān)系,如果接收者是view,則寫view.否則填params.

<x2c-config>
    <attr name="app:mixColor" toFunc="view.setMixColor(int)" />
    <attr name="android:layout_marginTop" toFunc="params.topMargin=int" />
</x2c-config>

4.通過X2C加載布局

在原先使用setContentView或inflate的地方替換,如下:

this.setContentView(R.layout.activity_main); --> X2C.setContentView(this, R.layout.activity_main);
LayoutInflater.from(this).inflate(R.layout.activity_main,null); --> X2C.inflate(this,R.layout.activity_main,null);

過程文件

原始的xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:layout_width="match_parent"
  android:layout_height="match_parent"
  android:paddingLeft="10dp">

  <include
      android:id="@+id/head"
      layout="@layout/head"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerHorizontal="true" />

  <ImageView
      android:id="@+id/ccc"
      style="@style/bb"
      android:layout_below="@id/head" />
</RelativeLayout>

生成的java文件

/**
 * WARN!!! dont edit this file
 * translate from {@link  com.zhangyue.we.x2c.demo.R.layout.activity_main}
 * autho chengwei
 * email chengwei@zhangyue.com
 */
public class X2C_2131296281_Activity_Main implements IViewCreator {
  @Override
  public View createView(Context ctx, int layoutId) {
        Resources res = ctx.getResources();

        RelativeLayout relativeLayout0 = new RelativeLayout(ctx);
        relativeLayout0.setPadding((int)(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,10,res.getDisplayMetrics())),0,0,0);

        View view1 =(View) new X2C_2131296283_Head().createView(ctx,0);
        RelativeLayout.LayoutParams layoutParam1 = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
        view1.setLayoutParams(layoutParam1);
        relativeLayout0.addView(view1);
        view1.setId(R.id.head);
        layoutParam1.addRule(RelativeLayout.CENTER_HORIZONTAL,RelativeLayout.TRUE);

        ImageView imageView2 = new ImageView(ctx);
        RelativeLayout.LayoutParams layoutParam2 = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,(int)(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,res.getDisplayMetrics())));
        imageView2.setLayoutParams(layoutParam2);
        relativeLayout0.addView(imageView2);
        imageView2.setId(R.id.ccc);
        layoutParam2.addRule(RelativeLayout.BELOW,R.id.head);

        return relativeLayout0;
  }
}

生成的映射文件

/**
 * WARN!!! don't edit this file
 *
 * author chengwei
 * email chengwei@zhangyue.com
 */
public class X2C127_activity implements IViewCreator {
  @Override
  public View createView(Context context) {
        View view = null ;
        int sdk = Build.VERSION.SDK_INT;
        int orientation = context.getResources().getConfiguration().orientation;
        boolean isLandscape = orientation == Configuration.ORIENTATION_LANDSCAPE;
        if (isLandscape) {
            view = new com.zhangyue.we.x2c.layouts.land.X2C127_Activity().createView(context);
        } else if (sdk >= 27) {
            view = new com.zhangyue.we.x2c.layouts.v27.X2C127_Activity().createView(context);
        } else if (sdk >= 21) {
            view = new com.zhangyue.we.x2c.layouts.v21.X2C127_Activity().createView(context);
        } else {
            view = new com.zhangyue.we.x2c.layouts.X2C127_Activity().createView(context);
        }
        return view;
  }
}

不支持

  • merge標(biāo)簽 ,在編譯期間無法確定xml的parent,所以無法支持
  • 系統(tǒng)style,在編譯期間只能查到應(yīng)用的style列表,無法查詢系統(tǒng)style,所以只支持應(yīng)用內(nèi)style

支持

  • 兼容ButterKnifer
  • 兼容DataBinding
  • 各種系統(tǒng)控件、自定義控件
  • include標(biāo)簽
  • viewStub標(biāo)簽
  • fragment標(biāo)簽(感謝Dreamskya)提出寶貴意見
  • 應(yīng)用style
  • 自定義屬性(感謝Anzhi-Meiying提出的寶貴意見)
  • 系統(tǒng)屬性
屬性名稱 屬性名稱
android:textSize app:layout_constraintRight_toLeftOf
android:textColor app:layout_constraintBottom_toTopOf
android:text app:layout_constraintTop_toTopOf
android:background app:layout_constrainedHeight
查看全部

github倉庫地址:https://github.com/iReaderAndroid/X2C

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容