文件组模板是基于FreeMarker模板语言的一个功能很强大的Android开发模板,可以这样说,代码片段模板和文件模板是一种提高编码效率的工具,而文件组模板可以算是一种模板引擎。
效果图展示
一图胜千言,先上图
已有工程中使用模板效果图
创建工程时使用模板
示例场景
在进行Android开发时,我们经常会创建一个Demo工程,目的可能有很多种,可能是为了验证一个问题,可能是为了学习一个框架的使用,可能为了测试自己写的一个lib库等等。这个时候我们可能会创建一个Activity,然后再在xml写一些按钮,再在Activity里写该按钮的事件监听逻辑,也就是说为了执行一段代码我们要做这么多操作。为了简化这段重复操作,我这边写了一个DebugActivity类,然后支持我们只需要写个子类来继承它,然后像下面这样写几个方法即可,运行的时候会根据方法动态创建按钮,并在点击按钮时执行该方法的代码逻辑。
1 | public void _test() { |
由于本文主要介绍模板相关的,所以该场景相关的具体代码技术细节就不多说了,有兴趣的可以看下,DebugActivity的代码,这里提出来只是为模板开发简单的做个铺垫。
模板位置
Android Studio Template中有系统预设的一些模板,我们可以直接修改,也可以另行添加新的模板。打开Android Studio安装目录/Contents/plugins/android/lib/templates
这个文件夹我们能看到下面的目录结构,这里便是AS中模板存放的位置。
我们接下来的工作也就在这里,保险起见我们在这里新建一个目录,我们自己写的模板都放在自己新建的目录里,例如我这里就创建了一个叫pk
的目录。
模板规范
在上面的基础上,我们可以直接打开/activies/EmptyActivity
目录,如下图
我们可以看到上面红色区域便是Template的文件结构,大致说下各个文件(夹)的含义
globals.xml.ftl
模板中参数配置的地方(可选)recipe.xml.ftl
模板行为执行处,引入这个模板之后,接下来要做什么事情,就是它说的算(可选,但是不选就没有意义了,因为模板引入是要要行为驱动的)root
存放模板文件及引入资源的目录,模板文件可以是.xml
、.java
、.gradle
等任何一个文本格式的文件,资源一般是我们引入的.png
资源文件(可选,不选同上)template_blank_activity.png
引入模板时的引导图(可选)template.xml
面向模板引擎的配置文件(必选)
我们可以看到,真正核心的部分就是root
、recipe.xml.ftl
和template.xml
,接下来这重点说明这三部分。
我们可以打开root目录,能够看到里面的文件除了图片资源文件都是以.ftl
结尾的,而.ftl
是标准的FreeMarker的文件。FreeMarker是类似于Velocity的一种模板框架,据说对于多文件处理时它具有更好的性能,大概也是Android Studio选择Velocity作为单文件模板,选择FreeMarker作为文件组模板的原因吧。有兴趣的可以去FreeMarker官网学习一下,它的自定义标签功能还是很强大的,个人感觉比Velocity的更加接地气。
接下来我们看一下recipe.xml.ftl
的内容,打开如下
1 | <?xml version="1.0"?> |
这里以<#
开头的都是FreeMarker的语法,基本上比葫芦画瓢就能看明白,就不多说了。其实对于这个文件最重要的部分是下面四个标签
copy
就是简单的copy,把模板root目录下的某个文件copy到目标工程的某个目录下instantiate
跟copy很类似,唯一多的一点功能就是并不只简单的走IO流进行copy,而是通过FreeMarker框架按照模板中的FreeMarker能识别的逻辑判断和数据引入来生成最终的目标文件merge
目标项目中有了某文件,而我们还要想该文件合并一些我们的模板的部分时,就选用merge,例如我们添加一个Activity时需要mergeAndroidManifest.xml
的配置。目前支持的merge格式有.xml
和.gradle
,但是对.gradle
支持的不怎么好,不过不影响该模板的开发,对于这套模板引擎的开发者来说,这可能是最麻烦的部分了,但是对于我们使用者就不用考那么多了,直接使用吧open
这个很简单,就是指定模板引入之后要IDE打开的文件
然后看下template.xml
内容
1 | <?xml version="1.0"?> |
当我们进行模板引入时,AS会弹出一个如下图的UI界面,要我们来填入或选择一些数据,例如输入Activity的的名称,选择SDK的版本之类的。而这个界面就是根据由该文件而来的。
内容比较多,为减少篇幅我挑些重要的说
template标签
name
引入模板时的模板名称,就死根据他选择哪个模板的description
弹出Dialog的标题,对应上去的区域1
category
表示该模板属于哪种分类,在引入的时候会有个分类的选择parameter
每个该标签就对应Dialog界面的一个输入项id
该参数的唯一标识符,也是我们在.ftl
中引入的值,例如定义的id为username
,引用时就是$username
name
对应Dialog上面该输入项的名称type
对应该参数的类型,Dialog就是根据这个来决定对应输入是选择框、输入框还是下拉框等等constraints
对应该参数的约束,如果有多个要用|
分割开suggest
建议值,这个输入部分是由级联效应的,可能你改了A参数,B参数也会跟着改变,就是根据这个参数决定的default
参数的默认值visibility
可见性,要配置一个boolean类型的参数,一般指向另一个输入源help
当焦点在某个输入源上面时,上图的区域3的就限制这儿的内容
操刀实战
了解了模板规范之后,我们编写模板时就不会那么被动了,下面我们来自己动手编写文章开始部分展示的模板。
首先在刚才提到的自定义的模板下创建如下图所示的目录结构
DebugActivity
root
src
app_package
DebugActivity.java.ftl
JumpActivity.java.ftl
SimpleActivity.java.ftl
AndroidManifest.xml.ftl
globals.xml.ftl
recipe.xml.ftl
template.xml
template_debug_activity.png
然后将下面的代码对应贴进去(图片部分随便找一张代替好了…)
globals.xml.ftl
1 | <?xml version="1.0"?> |
recipe.xml.ftl
1 | <?xml version="1.0"?> |
template.xml
1 | <?xml version="1.0"?> |
AndroidManifest.xml.ftl
1 | <manifest xmlns:android="http://schemas.android.com/apk/res/android"> |
DebugActivity.java.ftl
1 | package ${packageName}; |
JumpActivity.java.ftl
1 | package ${packageName}; |
SimpleActivity.java.ftl
1 | package ${packageName}; |
ok,到此对于该模板的编写过程就结束了,接下来重启下Android Studio,然后New Project
一路next下去,直到这个界面,这里就是我们自定义的DebugActivity模板了
下面是该模板的Github源码