Android studio插件开发实战(4)-CodeGenerator插件开发
2016-02-24 14:20
351 查看
上一篇文章分析了FindViewByMe插件的实现,这篇文章对它进行扩展,开发一款CodeGenerator插件。
上一张效果图:
网络请求可能是这样的:
也是模板化的代码。实现起来其实非常简单,就是简单的字符串操作。但是如果仅仅实现固定的转换未免太弱了,有一个小小的改动都要修改插件。能不能动态执行代码呢?
要实现动态执行代码有两种方式,第一种类似Excel里的脚本函数,定义一些CONCATENATE,SUBSTITUTE内置函数,根据函数做相应的操作。自己定义一套函数肯定不是做好的方式,费时费力又很难做好。第二种方式是直接执行java代码。定义一个java方法,拼接好字符串然后返回,没有任何学习新的函数的成本!
Java是真正的动态语言,可以在运行时利用反射机制动态调用对象的方法。
首先找到了这两篇文章,java中动态执行一段代码 , Java中动态加载jar文件和class文件无非是三部曲:生成java文件;编译成class文件;使用invoke方法执行方法。但是在执行第三步时怎么都报ClassNotFoundException for PluginClassLoader ,也就是插件的ClassLoader 无法装载我们编译出的class文件。把所有能试的ClassLoader试了一遍还是不行。无奈只能拼命搜索ClassLoader的内容,但是把关于Intellij 插件加载器的内容实在太少了。
最后只能去看JVM的知识了。很快,在深入理解Java虚拟机:JVM高级特性与最佳实践(第2版) 第九章找到了完美的解决方案。
首先我们要自定义一个ClassLoader,HotSwapClassLoader,如下:
它只做了一件事,将ClassLoader的protected方法defineClass变为public,这样就可以动态将class文件加载进虚拟机了。其实到这里问题已经解决了,类加载进来就可以执行成员方法了,执行结果可以通过字符串返回。
在书中作者又额外做了一步,将输入类的byte数组中代表java.lang.System的CONSTANT_Utf8_info常量修改为劫持后的HackSystem类,输出结果为该类向System.out/err输出的信息(具体做法请参加代码)。
扩展点1——newActivityInstance
首先想到的一个扩展点是自动生成activity的newInstance方法,作用是启动一个页面同时传递参数,因为每次去构造Intent传值再从Intent里取值都高度模板化,每次手写很烦,完全可以用插件自动生成。上一张效果图:
扩展点2——动态自定义模板
第二个扩展点是自动转换字符,比如我们的接口名字可能是”home.login”,我们想将它定义成常量,并添加注释:/** * Comments **/ public static final String HOME_LOGIN = "home.login";
网络请求可能是这样的:
/** * Comments **/ public void homeLogin() { NetworkParam param = new NetworkParam (Constants.HOME_LOGIN ); ... }
也是模板化的代码。实现起来其实非常简单,就是简单的字符串操作。但是如果仅仅实现固定的转换未免太弱了,有一个小小的改动都要修改插件。能不能动态执行代码呢?
要实现动态执行代码有两种方式,第一种类似Excel里的脚本函数,定义一些CONCATENATE,SUBSTITUTE内置函数,根据函数做相应的操作。自己定义一套函数肯定不是做好的方式,费时费力又很难做好。第二种方式是直接执行java代码。定义一个java方法,拼接好字符串然后返回,没有任何学习新的函数的成本!
Java是真正的动态语言,可以在运行时利用反射机制动态调用对象的方法。
首先找到了这两篇文章,java中动态执行一段代码 , Java中动态加载jar文件和class文件无非是三部曲:生成java文件;编译成class文件;使用invoke方法执行方法。但是在执行第三步时怎么都报ClassNotFoundException for PluginClassLoader ,也就是插件的ClassLoader 无法装载我们编译出的class文件。把所有能试的ClassLoader试了一遍还是不行。无奈只能拼命搜索ClassLoader的内容,但是把关于Intellij 插件加载器的内容实在太少了。
最后只能去看JVM的知识了。很快,在深入理解Java虚拟机:JVM高级特性与最佳实践(第2版) 第九章找到了完美的解决方案。
首先我们要自定义一个ClassLoader,HotSwapClassLoader,如下:
public class HotSwapClassLoader extends ClassLoader{ public HotSwapClassLoader() { super(HotSwapClassLoader.class.getClassLoader()); } public Class loadByte(byte[] classByte) { return defineClass(null, classByte, 0, classByte.length); } }
它只做了一件事,将ClassLoader的protected方法defineClass变为public,这样就可以动态将class文件加载进虚拟机了。其实到这里问题已经解决了,类加载进来就可以执行成员方法了,执行结果可以通过字符串返回。
在书中作者又额外做了一步,将输入类的byte数组中代表java.lang.System的CONSTANT_Utf8_info常量修改为劫持后的HackSystem类,输出结果为该类向System.out/err输出的信息(具体做法请参加代码)。
遗留问题
1、jdk版本不兼容问题,用java7 / 8 编译出的插件放到运行环境是java8 / 7的开发环境会不识别,目前只能分别使用java7和8编译出两个插件一起放到android studio插件目录。源代码
最后附上github地址, 可以直接下载CodeGenerator-jdk1.7.jar、CodeGenerator-jdk1.8.jar两个包放到android studio 的plugins目录下使用。相关文章推荐
- java自动生成验证码插件-kaptcha
- jQuery菜单插件用法实例
- 加载flash9.ocx出现错误的解决方法
- jquery实现的代替传统checkbox样式插件
- 10款新鲜出炉的 jQuery 插件(Ajax 插件,有幻灯片、图片画廊、菜单等)
- 推荐40个非常优秀的jQuery插件和教程【系列三】
- Node.js插件的正确编写方式
- 推荐十款免费 WordPress 插件
- 使用JavaScript开发IE浏览器本地插件实例
- jQuery实现的简单提示信息插件
- 推荐25个超炫的jQuery网格插件
- 纯JavaScript实现的分页插件实例
- JQuery插件jcarousellite的参数中文说明
- jQuery插件kinMaxShow扩展效果用法实例
- jQuery插件制作之全局函数用法实例
- 精心收集的jQuery常用的插件1000
- jQuery validate插件submitHandler提交导致死循环解决方法
- 40款非常棒的jQuery 插件和制作教程(系列二)
- 40款非常有用的 jQuery 插件推荐(系列一)
- FullCalendar日历插件应用之数据展现(一)