规范你的代码:AndroidStudio 一键生成MVP模板代码
题外话
很久之前就了解过Google的 todo-mvp的开发模式,但很长一段时间都不想用于实际项目中。主要原因就是感觉很麻烦。因为那时我用的开发模式是MVC,我理解的MVC很简单:布局文件表示View、Activity表示Control,然后我只需新建一个类作为Model就可以了,什么脏活累活都放在model处理,完了之后刷新布局。我的目的也很简单:保证我的Activty整洁干净...然而功能复杂后会让单薄的Model变得杂乱不堪~
相比MVC,以todo-mvp为例你新建一个MVP的Activty你还要建相关的 View、Model、Presenter、Contract等等的类和接口,而且各个类、接口间的继承和实现,眼花缭乱啊!这真的让刚接触的人望而止步,新增一个Activity都那么费劲了,如果一个项目下来会不会变得很臃肿?而且会额外新增巨大的工作量,种种担忧让我一直将MVP拒之门外,但随着项目越来越大,功能越来越复杂 MVC出现了明显的短板。再讲下去就有点跑题了,关于MVC和MVP的对比可以参考一下浅谈MVC、MVP。到这可能有孩子想说了:"别人都用MVVM了,你还用MVP,太low了!"。就像找媳妇一样,不是哪个漂亮就去娶谁,别人也不一定看得上你,合适的才是最重要的。
入正题
于是就一直琢磨着能不能在新建一个Activity的同时生成MVP所需要的所有类和接口。网上搜索一番,发现了Android Studio中自定义模板。因为对todo-mvp不太感冒于是参考了Android简单实用的MVP框架。
实现了以rxjava全家桶+retrofit+butterknife+eventbus+glide为技术栈的MVP模板。
因为在Create New Mvp Project的时候我会把retrofit和rajava等用到的框架进行依赖,而且会把所有封装的类如:retrofit工厂类、工具类等等常用的类导入进来,重点是把mvp的基类导入了进来供其他自定义模板使用。由于另外两个模板需要用到相关的框架和自定义类,所以必须要先用Create New Mvp Project这个模板创建项目。这样做目的主要是为了让大家快点看到效果,同时给大家一点灵感,从而创建出属于自己的一套模板,规范自己的代码,提高开发效率,早点下班!
直接上效果图(本人PS功底一般,模板的图就先随意放了)
1.新建一个项目
image2.选择模板
image3.设置参数
这里要注意的是你只需要填入 Input Your Name(开发者)和File Head Name(生成所有类的名称),其他的不用管,不要去修改Activity Name和Layout Name! 然后直接finish创建新项目。关于参数后面详解。
image4.生成MVP工程
生成MVP工程的同时会把你技术栈所用到的依赖添加进来,也包括常用的工具类、资源文件(自定义布局、动画文件、values下的所有配置文件等等),只要你用到的基本都能添加进来。如果你是一位经常要开发新项目的猿,此时是不是想喊我baba了。不用一块砖一块砖般过来了,一键新建项目后直接干就完了!如下图就是刚新建了工程的样子,这是我常用的工程结构。不用像以前那样新建项目后从其它项目把代码复制粘贴过来了,省心!
image5.新建一个新的MVP Activity或者 Fragment
注意!注意!注意!我定义的所有路径都是基于包名下的!!新建时一定要右击包名,然后选择自定义的模板!这里不要选Create New Mvp Project模板了这个是新建工程的,选Create New Mvp Activity Or Fragment或者RecyclerView Activity用于生成MVP模式的Activity或Fragment
image6.填写新增模块的参数
这里也只是修改Your Name和Component Name就可以了,然后选择新建Activity还是Fragment 然后点击finish即可。
image7.生成新的MVP模块
下图是新增了一个MVP Activity模板的样子,是不是轻轻松松就让项目规范了起来?一键生成mvp模式的代码不用做重复无用的工作,只用关心你的业务。
image到这里效果基本就演示完了,因为新建项目时就依赖了相关的框架和导入了封装好的类,所以可以直接进行网络请求如图:
image本人同时还另外还制作了RecyclerView Activity,相信大家使用RecyclerView都会觉得有点烦,又要新建一个adapter,又要新建列表里的子布局、数据的实体类。如果是分页列表的更烦,copy一堆接口和实现逻辑,现在可以一键生成是不是很爽?好了,讲那么多开始讲教程了,主要让大家会自己建立一个符合自己编码习惯的模板。我的模板只作抛砖引玉只用。
纯洁的微笑
第一步找到模板文件夹
在你Android Studio安装目录下找到 \templates\activities这个目录,可以看到这里面有很多自带的模板。而我们要做的就是选一个最简单最干净的模板copy在当前文件夹,重命名后进行改造。别幻想着一砖一瓦自己砌,随便打开个模板的脚本文件看那堆宏定义就足以让你怀疑人生。重点是经常报错,而且是找不到错在哪里那种。如果你有其他的模板,直接拷贝到这个目录下重启IDE即可使用。
image第二步拷贝EmptyActivity模板
image 然后按你们的想法把拷贝的这个模块重命名,接下来就可以进行改造了。先介绍这几个文件:
root:存放要导入的代码和资源文件。
globals.xml.ftl顾名思义是定义全局参数。
recipe.xml.ftl主要负责把root里面的文件导入到项目里。
template.xml主要负责定义新建模板时所需的参数。
template_blank_activity.png是模板的封面图片。
第三步修改模板参数文件template.xml
image image image这里我觉得最需要注意的地方就是<parmeter>标签里的id参数,其他地方需要用到这个<parmeter>的值只需要写&{id}即可引用,如我要用到id="componentName"的值只需要引用这个值得地方写${componentName}即可。而且我们可以在recipe.xml和代码、资源文件中使用。
第四步建立需要生成的资源文件
这里我用Create New Mvp Project的root讲解:
image我们要导入的类都放在root/src/app_package下, 这里我建议事先写好一个可以运行的Android 模板 Demo然后再一个一个修改移植到这个目录。第一步将要移植的文件加上.ftl,第二部打开文件修改里面的包名、类名等,不然新建出来的模板会飘红。
image如图,我们需要用freemarker语法定义包名类名,确保生成文件的位置和你定义的是一致的。这里用到的值都是我们之前在template.xml中定义的。上面我说过,如果要在工程新建mvp模板的Activity时必需是右击项目的包名新建。看上图第一行:package ${packageName}.activity意思就是在当前的包名下的activity包内新建一个Activity,所以一定要在该包名上操作,或者自行定义,其他文件的定义也是一样。这里要说一下的引用template.xml中的值时可能要进行判断,这时可以用
<#if 条件>
执行A
<#else>
否则执行B
</#if>
举个例子:比如你需要根据新建模板时获取的参数来创建不同的布局可以这样写:
<#if 条件>
setContentView(R.layout.activity_A);
<#else>
setContentView(R.layout.activity_B);
</#if>
在你的代码文件或者recipe.xml.ftl中都可以使用。
还有其他很多方法大家可以去发掘,鄙人能找到的这方面资料太少。
除了添加代码还可以添加AndroidManifest.xml,build.gradle还有res下的anim、layout、drawable、values等文件夹所以功能很是强大。
先说说比较简单的res
image像anim、drawable、layout、values这些资源问件一般直接拷贝过来就可以使用了,连.ftl后缀都不用添加在recipe.xml.ftl直接写copy把整个文件夹都拷贝到项目里就行,但是你如果想要对里面的文件进行操作的话,那个文件就必须加上.flt不然脚本语言无法执行文件而导致报错。
重点要讲下AndroidManifest.xml,build.gradle这两个文件了,也是坑最多的。AndroidManifest.xml里主要就是想添加权限,但是这里就出现了问题。如果有解决的方法的同学请赐教,鄙人琢磨了很久,因为找不到相关资料就不停的去尝试。发现在AndroidManifest.xml中只添加一条权限时时没问题的,但是添加多条权限后生成的代码格式就乱了,还有就是build.gradle里依赖多个库没问题,但要想在android {}添加多行配置就出现问题了。目前解决的方法还是一行一行的添加配置。比如我要在android {}里添加
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
这里就要分两次merge进gradle里面 ,如下图
image我要建立一个文件a内容是:
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
}
}
文件b内容是:
android {
compileOptions {
targetCompatibility JavaVersion.VERSION_1_8
}
}
通过这两个文件我才能把把内容merge进build.gradle里面。当然我最希望是把所有配置和依赖写入build.gradle然后导进去就好了,但是均已失败告终。原因可能很多,一是资料太少无法深入研究,基本都是靠参考系统自带的模板 进行学习。二是可能这方面的功能不是很稳定,因为我用的是3.1.3版本的AndroidStudio,把运行完美的模板交给了使用2.1的朋友结果报错了,里面的坑还是多哈。
上面已经准备好了生成模板的资源,现在就准备把这些资源按我们定义生成在项目里。这时就要用到recipe.xml这个文件了。
image这里主要是用到了3个标签将我们定义好的文件生成在项目里
1.merge合并,把你的资源文件的内容合并到目标文件。像AndroidManifest.xml和build.gradle只能用merge,如果想直接替换文件里面有很多问题要处理。公共模板文件里面有很多文件相互调用,而且都是用脚本语言、宏定义写的,水平有限就只能用水平有限的方法处理了。
2.copy拷贝,顾名思义就是把你的资源文件直接拷贝到对应的路径下了。
3.instantiate 实例,使用后加上个人理解应该是资源文件在对应的路径下生成一个实例。
其中关于路径我都是参考系统其他模板里面定义的,其中
${escapeXmlAttribute(manifestOut)}表示AndroidMainfest.xml所在目录;
${escapeXmlAttribute(projectOut)}表示项目下的app文件夹路径,和src文件夹同一层级
${escapeXmlAttribute(resOut)}表示资源文件的根目录即res文件夹
${escapeXmlAttribute(srcOut)}表示表示项目代码文件的根目录
最后open标签建新模板后AndroidStudio打开目标文件。
我刚开始写recipe.xml的时候在想怎么在工程里新建一个目录,然后我再把代码文件导入到我新建的目录。后来发现并不需要那么麻烦
<instantiate from="root/src/app_package/ModelImple.java.ftl" to="${escapeXmlAttribute(srcOut)}/implement/${componentName}ModelImple.java" />
在
to="${escapeXmlAttribute(srcOut)}/implement/${componentName}ModelImple.java"
中,implement代表路径,只要你写上路径就会为你直接生成相应的文件夹。
到这基本就结束了,这里是代码地址,只需要把模板文件放在\Android Studio\plugins\android\lib\templates\activitie下即可使用,有问题欢迎指出,谢谢。