X2J 即 XML to Java。
Android X2J是一个 Gradle 插件,它可以在 APK 编译期间 自动 将你的 XML 布局翻译成 Java 代码,并 自动 注入到 Activity 和自定义布局中。
传统的布局加载方案都是在运行时解析 XML(通过 LayoutInflater),而 Android X2J 则可以将 XML 的解析提前到编译时,从而可以让布局加载速度提升 200%。
了不起的 X2C
不知道你是否了解过 X2C 这个库。简单来说,X2C 会在编译时,将 XML 布局翻译成对应的 Java 代码。
原始的 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>
X2C 生成的 Java 文件
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;
}
}

X2C 的想法很大胆,既保留了 XML 的优点,又解决了它带来的性能问题。但是它使用起来就不那么友好了。
// this.setContentView(R.layout.activity_main);
X2C.setContentView(this, R.layout.activity_main);
和原来的写法相比,X2C 明显具有较强的侵入性。
为了解决这个问题,你可以试试 Android X2J。
Android X2J 的特点
Android X2J 是一个 Gradle 插件,它可以让你 零成本 使用 X2C。 它甚至可以让你在完全不了解 X2C 的 API 和用法情况下,就可以享受到 X2C 的功能。

首先,Android X2J 会自动为你在 dependencies 中添加 X2C 的相关依赖,并生成相关的 @Xml 注解。
其次,当然也是最重要的一点,Android X2J 使用了 gradle transform api,在 APP 构建期间自动将 java 字节码做如下转换。
activity.setContentView(R.layout.activity_main)
=>> X2J.setContentView(activity, R.layout.activity_main)
layoutInflater.inflate(R.layout.view_item, parent)
=>> X2J.inflate(layoutInflater, R.layout.view_item, parent)
View.inflate(context, R.layout.view_item, parent)
=>> X2J.inflate(context, R.layout.view_item, parent)
X2J类是对X2C类的封装。
下面是项目里 sample 模块里面的 MainActivity 的源码:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LayoutInflater.from(this).inflate(R.layout.fragmetn_layout, null);
LayoutInflater.from(this).inflate(R.layout.fragmetn_layout, null, false);
}
}
而下面则是使用了 X2J 插件打包后的 apk 反编译后的对应代码。
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
X2J.setContentView(this, R.layout.activity_main);
X2J.inflate(LayoutInflater.from(this), (int) R.layout.fragmetn_layout, null);
X2J.inflate(LayoutInflater.from(this), (int) R.layout.fragmetn_layout, null, false);
}
}
最后,如果你已经使用了 Android X2J 插件然后又想弃坑,这很容易就能做到。 因为它只不过是一个 gradle 插件而已,没有任何侵入性。
!> 注意,因为 X2C 自身的原因,目前 Android X2J 并不支持 kotlin-kapt。
使用方法
- 配置根目录的 build/gradle。
buildscript {
repositories {
// ...
maven { url "https://jitpack.io" }
}
dependencies {
classpath 'com.github.7hens:android-x2j:1.0'
}
}
- 在 app/build.gradle 中使用插件。
// 必须在 android {} 代码块之后添加插件。
// 如果你不想使用 X2J 了,把这行注释掉就行了。
apply plugin: 'android-x2j'
- 好了,接下来 Android X2J 会自动把 XML 布局翻译成 Java 代码(当然,这归功于 X2C),并打包到 APK 中。
This is amazing !! Github 项目地址
后记:理想是丰满的,现实是骨感的。我拿 Android X2J 到已有的项目中试了一下,发现编译不通过。 看了一下,原来是因为 X2C 的原因,它翻译出来的 Java 代码有问题。 目前 X2C 无法识别 XML 中的类似于
?android:attr/windowBackground和@android:color/white的系统属性。
