一款超实用的快速从xml中提取字符串到strings的插件

一、引言

新进一家公司,给的第一个任务便是做硬编码优化,要做的事情大概是,把xml中写死的dp、sp、color、文字等,全部映射到dimen.xml和strings.xml中,初步分析,对于dp、sp、color这些并不难,利用正则很快就能替换完,可是字符串又该如何替换呢?难道要一个个布局文件找,并且一个个改么,作为程序员,自然不愿意做这种体力活,如是今天的主角ExtractText登场了,废话不多说,看动画效果。

二、使用方法

  1. 在studio中安装插件,搜索ExtractText即可,安装方法自行查阅,也可去JetBrains直接下载插件的jar,文末已给出下载地址。
  2. 鼠标选中layout文件下的布局文件,点开工具栏中的Code→ExtractText,也可以利用快捷键 ctrl+alt+B,此时会看到底部显示翻译中,成功后会有提示。
  3. 也可以选中java文件中的布局文件的名字,如下:需要选中activity_main,这是最开始设计时使用的方法,后来考虑到这样的话需要点开每个java文件并找到其中的布局文件,这样操作太麻烦,然后就想到是不是可以直接选中layout下的布局文件,如是就实现了第二步的方式,但此方式依然保留。
setContentView(R.layout.activity_main)

三、实现原理

插件开发这一块不在此赘述,有兴趣的可以自行百度。我说下ExtactText的实现原理:

  1. 获取到布局文件的名字,根据使用方法中介绍的可知,此插件中实现了两种获取布局文件名字的方法,第一种是获取用户鼠标选中layout文件夹下的具体布局文件,第二种是获取用户鼠标选中的java文件里的布局文件。
  2. 知道需要处理的布局文件的名字,我们便可以通过下面代码获取到布局文件的对象
        //获取布局文件
        PsiFile[] filesByName = FilenameIndex.getFilesByName(project, layoutName + ".xml", GlobalSearchScope.projectScope(project));
  1. 有了布局文件,我们需要想好哪些字符串是需要替换的,此处先上一份布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv2"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:gravity="center"
        android:text="小城故事" />

    <EditText
        android:id="@+id/et_username"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:background="@null"
        android:gravity="center"
        android:hint="提示语"
        android:text="让我们荡起双桨,小船儿随风波浪" />

    <CheckBox
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        android:layout_gravity="center"
        android:text="刘德华" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        android:layout_gravity="center"
        android:text="提交" />

    <TextView
        android:id="@+id/tv_first"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:gravity="center"
        tools:text="浮夸" />

    <TextView
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:gravity="center"
        android:text="@string/activity_main_rxjava" />
        
</LinearLayout>

经分析可知,需要替换的字符串有:

android:text="小城故事"
android:hint="提示语"
android:text="让我们荡起双桨,小船儿随风波浪" 
android:text="刘德华"
android:text="提交"

不需要替换的字符串有:

tools:text="浮夸"
android:text="@string/activity_main_rxjava"

总结替换规则:利用上一步获取到的布局文件对象,循环读取布局文件里的每个控件中包含“android:text”和“android:hint”标签所对应的值,并剔除掉以“@string”开头的字符串,然后将剩余需要替换的字符串放到集合中。

  1. 找到了需要替换的字符串后,这一步要做的就是字符串映射了,而字符串映射我们通常的做法便是,将字符串翻译成英文,以下划线拼接起来作为key,需要替换的字符串作为值,然后写到strings.xml文件中。此处翻译我借鉴的是翻译插件AndroidLocalizationer的源码中使用的google的翻译接口,此接口支持将多个需要翻译的内容拼接成get请求,这也是我上一步为何要将需要翻译的字符串存放到集合中,也是为了在这里方便拼接翻译的请求url。

  2. 翻译的接口返回的是json字符串,这里我们将它解析成集合的形式返回,然后和需要翻译的字符串匹配,重新生成存放翻译对象的集合,便于下一步拼接字符串的key。

  3. 定义字符串的key,此处我采用的规则是以布局文件的名字拼接翻译后的值,如果翻译后的值的长度超过5我会用数字代替。

  4. 在strings.xml中写入映射文件,根据生成的key和第一步获取到的value,拼接成需要的内容并写入strings.xml中,此处为了做好区分,会在头部和尾部做分割线标识,具体拼接规则可看代码。当然,如果觉得这种拼接规则不妥可以修改插件源码,定制自己想要的规则,文末已给出源码地址。

    /**
     * 拼接strings.xml中需要显示的内容
     */
    private String getShowContent(List<DataBean> attributeValues) {
        StringBuilder block = new StringBuilder();
        block.append("\n");
        for (DataBean dataBean : attributeValues) {
            block.append(")
                    .append(dataBean.getKey())
                    .append("\">")
                    .append(dataBean.getValue())
                    .append("\n");
        }
        block.append("\n");
        return block.toString();
    }
  1. 替换布局文件中的值,将android:text=“value"替换为android:text=”@string/key",这里是读取到布局文件的内容,做字符串替换来实现的。

四、注意问题

  1. 使用此插件需保持网络通畅,因为需要调用google翻译的接口。
  2. strings.xml中生成的映射文件是从倒数第二行开始写入的,所以为了保证写入的内容在《resources》标签内部,务必保证《resuources》标签下面没有多余的行。

五、缺点及待优化

  1. 只支持android:text=“value” 和 android:hint="value"这两种标签中字符串的替换,对自定义控件因为没有特定的规则,无法替换,需要手动修改。
  2. 一次只能替换一个布局文件,后续会考虑是不是可以同时选中多个布局文件,一次性替换,或者直接选中layout文件夹,一次性将layout文件夹下所有的布局文件做替换
  3. 如果同一个布局文件中有多个相同的需要替换字符串的文字,会在strings.xml中生成多个映射。
  4. 目前不支持类文件中的字符串替换

五、资源地址

项目源码
插件下载地址

六、感谢

AndroidLocalizationer
KViewBind

你可能感兴趣的:(java技术篇)