android开发的同学,相信都遇到过在写代码的过程中,需要花费很多时间去做一些重复的劳动,比如下面这些:
- activity和fragment创建后要写一大堆的findViewById来初始化各个view
- 创建一个列表ListActivity的界面,我需要配套创建相关的一大堆文件包括:
- activity、fragment、adapter、listener等class
- activity layout、fragment layout、list item layout等layout
- Model层相关的比如我们是用retrofit就包括:manager、service、request、response四个类文件
如果上面这些文件一个个创建,累死之余build时候发现各种缺漏
- 调试时候每次都要build一两分钟,上个洗手间回来,发现gradle任务还在运行中
- 调试webview时候,只能chrome来模拟,调试好了,真机上又有问题
- app的数据http请求调试各种繁琐,又加代理连到pc,又要开charles,手机又要连内网,手机的wifi代理经常要反复切换,坑爹的居然没有自动保存代理功能
上面这些提到的没有技术含量得“体力活”,可能会占据了我们开发不少的时间,一方面浪费时间、另一方面无法专心开发具体业务需求,我下面总结了一下消灭这些体力活的方法
依赖注入DI(Dependency Injection)
估计大家对DI应该有所了解,因为在android开发里面,这是最浪费体力活的工作,前不久,我所负责的项目android版本需要新增一个新的模块,新的模块流程复杂、交互比较多,开工之前预计至少要3周时间开发,我决定尝试使用一个DI库 Butterknife来开发,配合android studio插件使用,自从用起来后,写代码的心情就一个字:很爽!并且最终整个模块提前一周时间基本功能都写出来。
一些常见的android DI库包括
- Android Annotation
- Dagger
- RoboGuice
- ButterKnife
上面DI库用起来都是大同小异,而且性能都很好,因为它们基本都是编译时生成缓存来提供运行时使用,而不是运行时反射来调用。
Android Annotation看上去功能最强大,支持大量的注解,除了view,event,还包括各种你可以想到的注入,比如service、resource、多线程、甚至还包括http服务注入!
看下面官网的例子截图,使用Android Annotation后,代码简洁得异常残暴!!!
不过最终我们还是选择了ButterKnife,它比较轻量级,如果直接就上AA,担心步子迈得太大,大家不(rong)太(yi)习(che)惯(dan),不过其实最主要原因还是因为Butterknife提供了IDE插件,其实我们的android项目之前也有一套自己写的简单的ViewInject的注解,但是没有插件支持,所以插件支持很重要,它能真正帮助我们解放体力活。
下面是ButterKnife的使用介绍动画
另外插件还可以配置生成view的私有变量的前缀,比如统一前面加“m”前缀
批量生成通用模块的模版
我前面一开始所提到的创建一个列表时候,所需要创建一大堆文件,而且这些文件零零散散分布在各个文件夹,这也是一件很繁琐的体力活。
我使用了一个完全没有技术含量的方法来做这些“体力活”,我在项目里面创建了一个工具,然后通过自定义模块来生成需要的文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| public class CreateListActivity { public static void main(String[] args) { System.out.println("===== Create listactivity start ====="); String model = args[0]; System.out.println("model:" + args[0]); String currProjectPath = System.getProperty("user.dir"); String tmpPath = currProjectPath + "/template/listactivity"; String appPath = currProjectPath + "/../app/src/main/java/com/netease/mail/oneduobaohydrid/"; String resPath = currProjectPath + "/../app/src/main/res/layout/"; String tmpActivityFile = tmpPath + "/Activity.java"; String activityFile = appPath + "activity/" + Util.upperCaseModel(model) + "Activity.java"; String tmpAdapterFile = tmpPath + "/Adapter.java"; String adapterFile = appPath + "adapter/" + Util.upperCaseModel(model) + "Adapter.java"; String tmpFragmentFile = tmpPath + "/Fragment.java"; String fragmentFile = appPath + "fragment/" + Util.upperCaseModel(model) + "Fragment.java"; String tmpActivityXml = tmpPath + "/activity.xml"; String activityXml = resPath + "activity_" + model + ".xml"; String tmpFragmentXml = tmpPath + "/fragment.xml"; String fragmentXml = resPath + "fragment_" + model + ".xml"; String tmpItemXml = tmpPath + "/layout_item.xml"; String itemXml = resPath + "layout_item_" + model + ".xml"; System.out.println("tmpPath:" + tmpPath); System.out.println("appPath:" + appPath); Util.buildFile(tmpActivityFile, activityFile, model); Util.buildFile(tmpAdapterFile, adapterFile, model); Util.buildFile(tmpFragmentFile, fragmentFile, model); Util.buildFile(tmpActivityXml, activityXml, model); Util.buildFile(tmpFragmentXml, fragmentXml, model); Util.buildFile(tmpItemXml, itemXml, model); System.out.println("===== Create listactivity finish ====="); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class CreateModel { public static void main(String[] args) { System.out.println("===== Create model start ====="); String model = args[0]; System.out.println("model:" + args[0]); String currProjectPath = System.getProperty("user.dir"); String tmpPath = currProjectPath + "/template/model"; String modelPath = currProjectPath + "/../model/src/main/java/com/netease/mail/oneduobaohydrid/model/" + model.toLowerCase(); System.out.println("tmpPath:" + tmpPath); System.out.println("modelPath:" + modelPath); File file =new File(modelPath); if (!file.exists() && !file.isDirectory()){ file.mkdir(); Util.buildFiles(tmpPath, model, modelPath); } else { System.out.println("!!!!!Model目录已存在" + modelPath + ""); } System.out.println("===== Create model finish ====="); } }
|
两个task分别创建ListActivity任务和创建Model任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| task createModel (type: JavaExec, dependsOn: classes) { if(project.hasProperty('model')){ args(model) } main = 'com.templateutil.CreateModel' classpath = sourceSets.main.runtimeClasspath }
task createListActivity (type: JavaExec, dependsOn: classes) { if(project.hasProperty('model')){ args(model) } main = 'com.templateutil.CreateListActivity' classpath = sourceSets.main.runtimeClasspath }
|
1
| harry$ gradle createListActivity -Pmodel=wishlist
|
缩短gradle build task的时间
现在一些大型的android项目,里面可能存在多个module,依赖很多库,每次需要run或者debug时候,需要一两分钟时间等待task run完,才能调试,下面有三个方法缩短这个build时间
修改gradle配置,
爆栈里的这个修改gradle配置方法经过实践证明确实可以减少一点build时间,在我的项目里面大概可以减少10-20s
来自facebook的buck,据说可以将build时间缩短到十分之一,WOW!不过我没有用过,因为看介绍说,它放弃了gradle的build system,并且需要修改大量的代码,所以我们放弃用它
当看到LayoutCast README的第一行说明,我忍不住想跟作者握个抓
Android SDK sucks. It’s so slow to build and run which waste me a lot of time every day.
LayoutCast最大的好处是,不需要修改太多的代码,速度方面在介绍中有数据对比,据称比buck还要快,我试过放入我们的项目,可能是因为我们的项目结构比较复杂module比较多,一直没有运行成功,不过我新建project测试是可以用的
webview调试插件
有个很好用的调试真机webview的chrome插件,通过adb连接直接调试真机,而不需要chrome模拟移动设备
最后这个是一个小工具,使用adb命令可以快速进行wifi代理的设置和清除,亲测有效!