咱们知道Android Studio是基于Intellij的一套IDE环境,Intellij自己为开发者提供了插件式的开发环境,大大提升了开发效率和IDE可配置化。目前studio的成熟插件已有不少。 咱们这里先来看看目前已有的主流Studio插件有哪些,几乎已经涵盖了你全部的需求: juejin.im/entry/59980…前端
把studio工做中技术含量低,重复性高的工做,用插件形式代替。java
插件名称 | 插件功能 |
---|---|
GsonFormat | (jsonString自动生成JavaBean类) |
ButterKnife Zelezny | (xml自动生成butterknife的注解代码) |
Code Generator | (xml自动生成activity fragment) |
AndroidProguardPlugin | (根据依赖的第三方库,生成proguard文件) |
Exynap | (更加扩展,把成型、固定的代码段,自动生成) |
MVPHelper | (自动生成 M V P 到不一样文件夹) |
为了开发的方便,将studio自己不具有的功能引入,扩展IDE的功能,避免studio和第三方来回切换和数据传输的麻烦。node
插件名称 | 插件功能 |
---|---|
EventBus3 Intellij | (辅助 索引eventbus 从subscribe到post,提升eventbus可读性) |
GradleDependenciesHelperPlugin | (gradle依赖自动补全) |
SQLScout | (调试sqlite) |
FindBugs-IDEA | (findbugs插件) |
Android Methods Count | (预览依赖库中方法数,提早判断方法数超限) |
各插件的开发和使用成熟度很高,大部分是免费而且开源的,活跃度也很高。由于studio的使用率极高,并且IntelliJ IDE自己的插件资源丰富,直接借鉴的插件也有不少,使得插件开发的门槛大大下降。 那么咱们本身再遇到重复性高的工做,或者第三方功能须要嵌入时,也建议考虑插件的方式。android
一、Preferences - plugins - Browse repositories 查找jetBrains远程仓库上的插件 不少插件是免费且开源的(github),远程repositories上对应的plugins都是最新的release版本 咱们可使用beta版本,或者本身对开源插件进行二次开发,这时就须要安装本地插件:git
二、Preferences - plugins - Install plugin from disk 查找本地plugin的jar包github
本文会以一个我本身二次开发的plugin为例,记录下plugin开发的基本流程和值得注意的坑。sql
studio是基于IntelliJ的二次开发的IDE,因此plugins实际上是IntelliJ的插件,IntelliJ这个IDE自己就能够开发plugins,IntelliJ下载免费版便可,官网下载,community版本够用。再也不赘述。json
新建project不少文章都有讲,不赘述,能够参考:www.jianshu.com/p/336a07b9d… 基本是配置IntelliJ sdk、建立plugin project、而后在plugin.xml中配置此插件便可bash
重点说下import工程,若是你是二次开发一个插件,那么import一个github已有的工程是必须的。以GsonFormat为例(github.com/zzz40500/Gs… github工程下,分为两个分支master和dev_1.2.2其中dev开发分支能够直接用于二次开发。(master分支直接import做为project,须要IDE配置不少东西)架构
dev分支工程配置步骤
import成功后,咱们看一下plugin工程是怎样的? plugin工程中常见如下三类文件,也是plugin工程较为特有的文件类型:
Action 做为整个插件的入口类,其入口方式和name等定义在plugin.xml,Action中actionPerformed做为入口方法,初始化当前类,包,传入到dialog中
Dialog 相似于android中的activity,绑定了Form类,用于view的databinding和逻辑 JsonDialog是入口dialog,FieldsDialog是解析jsonstring后展现的dialog,SettingDialog是配置dialog
GUI Form 相似于android中xml布局文件,只不过此处是swing的拖拽控件,Form与Dialog是配对出现,其对应关系在Form配置。
以GsonFormat plugin为例,具体讲清楚plugin工程的组成和实现原理。 (GsonFormat插件是把jsonString转变为javaBean的前端插件,写业务代码的朋友们应该很是熟悉,这款插件的使用过程是这样子的:) 第一步:弹窗:输入你要转换的jsonString,此处也能够Setting进行配置
主Action是MainAction,做为插件的入口能够看到他启动了弹窗JsonDialog。工程中维护了几个dialog(包括java文件和form表单文件),分别对应插件工做中全部的弹窗,被放入了ui文件夹。
处理流程的代码逻辑是流式的,从MainAction入口开始看起,在JsonDialog中点击肯定后,开始解析jsonString。 类JsonUtilsDialog中,点击事件的响应函数做为入口:
editTP.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent keyEvent) {
super.keyReleased(keyEvent);
if (keyEvent.getKeyCode() == KeyEvent.VK_ENTER) {
onOK();
}
}
});
复制代码
1.解析的过程,主要在ConvertBridge类完成,由run方法做入口,开始解析jsonSTR onOK()方法的实现:
private void onOK() {
//省略部分:get PsiClass generateClass:
new ConvertBridge(
this, errorLB, jsonSTR, mFile, mProject, generateClass,
mClass, generateClassName).run();
}
复制代码
2.ConvertBridge类中run方法,经过parseJson方法,开始解析jsonString,
public void parseJson(JSONObject json) {
if (Config.getInstant().isVirgoMode()) {
//省略代码:装配mGenerateEntity对象
//createFields 解析jsonString核心方法
mGenerateEntity.setFields(createFields(json, fieldList, mGenerateEntity));
FieldsDialog fieldsDialog = new FieldsDialog(mJsonUtilsDialog, mGenerateEntity, mFactory,
mGeneratClass, currentClass, mFile, project, generateClassName);
} else {
mGenerateEntity.setFields(createFields(json, fieldList, mGenerateEntity));
WriterUtil writerUtil = new WriterUtil(null, null, mFile, project, mGeneratClass);
writerUtil.mInnerClassEntity = mGenerateEntity;
writerUtil.execute();
}
}
复制代码
分为Virgo模式和非Virgo模式(默认virgo模式):virgo模式,就是启动FieldsDialog,就是咱们见到的第二个窗口,用户自行修改fields的定义,非virgo比较简单,跳过dialog直接写入fields到class里。除非settings本身定义,不然咱们通常都使用virgo模式。能够看到不管是否virgo模式与否,都会调用createFields方法,区别只是是否显示FieldsDialog。
3.详细看下createFields方法作了什么。
for (int i = 0; i < list.size(); i++) {
String key = list.get(i);
Object type = json.get(key);
if (type instanceof JSONArray) {
//将jsonArray放入listEntityList
listEntityList.add(key);
continue;
}
FieldEntity fieldEntity = createFiled(parentClass, key, type);
fieldEntityList.add(fieldEntity);
}
for (int i = 0; i < listEntityList.size(); i++) {
//解析listEntityList中数据
String key = listEntityList.get(i);
Object type = json.get(key);
FieldEntity fieldEntity = createFiled(parentClass, key, type);
fieldEntityList.add(fieldEntity);
}
复制代码
经过createFields方法把field放入FieldEntity,DataWriter再根据FieldEntity的内容写入class中,
4.以上的解析过程,只涉及了一层JavaBean的状况,JavaBean大部分状况下,是要嵌套Bean内部类的,就是JSONObject内部是嵌套jsonobject的,咱们继续来看:
private FieldEntity typeByValue(InnerClassEntity parentClass, String key, Object type) {
if (type instanceof JSONObject) {
InnerClassEntity classEntity = checkInnerClass((JSONObject) type);
if (classEntity == null) {
//省略代码
} else {
FieldEntity fieldEntity = new FieldEntity();
fieldEntity.setKey(key);
fieldEntity.setTargetClass(classEntity);
fieldEntity.setType("%s");
nodeBean = fieldEntity;
}
}
复制代码
createFields方法中对每一个fieldEntity依次调用createField方法,createFiled方法中调用了typeByValue方法,在createInnnerClass中 对子json再次进行createFields方法,如此依次递归。完成了一层层javabean的解析工做。 能够说Class中包括FieldEntry,而FieldEntry自己也是包含多个子FieldEntry的。FieldEntry能够设置基本类型,也能够设置ClassEntity。
5.最终经过WriterUtil类将FieldEntry写入到class文件中,完成了整个的插件功能。
因为代码混淆的缘由,开发中常常遇到debug下正常的代码,在release包状况下没法正常解析网路数据,由于javabean类中的field混淆后已经不是原来定义的名称了。而这个问题在提测关口最容易出现。想解决这个问题必须保证javaBean在打包中不被混淆。 如何不被混淆,不一样厂商有不一样的解决策略(规范):
通常咱们的接口管理系统中,均可以产生mock的jsonString,客户端开发会直接利用SGsonFormat插件将jsonString直接转为JavaBean,因此基于GsonFormat功能二次开发,让全部的JavaBean class统一继承Serializable,这样兼顾了易用性和统一性。
统一继承Serializable的逻辑,应该放入DataWriter写入的流程中,分析可得:在ClassProcessor中process方法,实际上将classContent的String内容经过PsiElementFactory写入class文件中,因此修改String classContent既可。
protected void generateClass(PsiElementFactory factory, ClassEntity classEntity, PsiClass parentClass, IProcessor visitor) {
onStartGenerateClass(factory, classEntity, parentClass, visitor);
PsiClass generateClass = null;
if (classEntity.isGenerate()) {
if (Config.getInstant().isSplitGenerate()) {
try {
generateClass = PsiClassUtil.getPsiClass(
parentClass.getContainingFile(), parentClass.getProject(), classEntity.getQualifiedName());
} catch (Throwable throwable) {
throwable.printStackTrace();
}
} else {
//根据classContent建立class
String classContent =
"public static class " + classEntity.getClassName() + " implements Serializable" + "{}";
generateClass = factory.createClassFromText(classContent, null).getInnerClasses()[0];
}
if (generateClass != null) {
//递归调用,建立内部类
for (ClassEntity innerClass : classEntity.getInnerClasss()) {
generateClass(factory, innerClass, generateClass, visitor);
}
if (!Config.getInstant().isSplitGenerate()) {
generateClass = (PsiClass) parentClass.add(generateClass);
}
//建立内部变量
for (FieldEntity fieldEntity : classEntity.getFields()) {
generateField(factory, fieldEntity, generateClass, classEntity);
}
//建立内部变量getter setter方法
generateGetterAndSetter(factory, generateClass, classEntity);
generateConvertMethod(factory, generateClass, classEntity);
}
}
onEndGenerateClass(factory, classEntity, parentClass, generateClass, visitor);
if (Config.getInstant().isSplitGenerate()) {
formatJavCode(generateClass);
}
}
复制代码
插件下载地址:(该插件已提交repository) plugins.jetbrains.com/plugin/1110… 或者直接搜索SGsonFormat,install便可使用
二次开发的改动并不大,可是把Studio的plugin开发环境和流程算是熟悉了一遍,plugin插件的开发能够说你会用java就能上手,只不过他自定义的文件类型和组织方式须要熟悉。若是有须要的话,作个新的plugin提升工做效率,是个很好的方式。