版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
【移动应用开发技术】3000行代码怎样简化成300行?来,一文来教你!
前言
APT(AnnotationProcessorTool)是用来处理注解的,即注解处理器。
APT
在编译器会扫描处理源代码中的注解,我们可以使用这些注解,然后利用
APT自动生成
Java代码,减少模板代码,提升编码效率,使源码更加简洁,可读性更高。1、具体场景下面我将会以项目中常见的intent页面跳转为例,给大家演示一下,如何自动生成
intent代码,以及对
getIntent的参数自动赋值。
要实现上面这个功能我们需要了解
APT、以及
JavaPoet。如果不太了解的同学可以先去了解一下。要实现上面这个功能我们需要了解
APT、以及
JavaPoet。如果不太了解的同学可以先去了解一下。
常用写法
Intent
intent
=
new
Intent(this,OtherActivity.class);
intent.putExtra("name",name);
intent.putExtra("gender",gender);
startActivity(intent);
数据获取
String
name
=
getIntent().getStringExtra("name",name);
String
gender
=
getIntent().getStringExtra("gender",gender);上述代码很必要但重复性又很高,写多了会烦,又浪费时间。并且在数据传递与获取时
key
值都需要保持一致,这又需要我们新建很多的常量。所以,这里我们希望上述的数据传递与获取可以自动生成。
为了实现这个需求,我们需要实现如下功能:
1)自动为
OtherActivity类生成一个叫做
OtherActivityAutoBundle
的类
2)使用建造者模式为变量赋值
3)支持
startActivity
或
startActivityForResult
跳转
4)支持调用一个方法即可解析
Intent
传递的数据,并赋值给跳转的
Activity
中的变量
我们需要自动化如下代码:
new
OtherActivityAutoBundle()
.name("小明")
.gender("男")
.start(this);//或
startActivityForResult(this,requestCode)
在OtherActivity中,自动为变量赋值:
new
OtherActivityAutoBundle().bindIntentData(this,getIntent());
a、创建一个JavaLibrary,并创建注解类
例如:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.CLASS)
public
@interface
AutoBundle
{
boolean
exclude()
default
false;//不参与
intent、bundle
传值
boolean
addFlags()
default
false;//添加
activity
启动方式
boolean
isCloseFromActivity()
default
false;//是否关闭
FromActivity
boolean
isBundle()
default
false;//是否使用
Bundle
对象传值
boolean
isSerializable()
default
false;//是否是
Serializable
类型
boolean
isParcelable()
default
false;//是否是
Parcelable
类型
boolean
isParcelableArray()
default
false;//是否是
ParcelableArray
类型
boolean
isParcelableArrayList()
default
false;//是否是
ParcelableArrayList
类型
}
b、再创建一个JavaLibrary,并将上一步JavaLibrary添加进来
此时,我们还需要在该Library中创建
resources
文件夹;接着在
resources
中创建
META-INF
和
services
两个文件夹;然后在
services
中创建一个名为
cessing.Processor
的文件。最后在该文件中写入我们注解处理器的全路径。此时,我们还需要在该Library中创建
resources
文件夹;接着在
resources
中创建
META-INF
和
services
两个文件夹;然后在
services
中创建一个名为
cessing.Processor
的文件。最后在该文件中写入我们注解处理器的全路径。
这里我们也可以使用自动化工具
implementation'com.google.auto.service:auto-service:1.0-rc2'
感兴趣的去搜一下具体用法这里我们也可以使用自动化工具
implementation'com.google.auto.service:auto-service:1.0-rc2'
感兴趣的去搜一下具体用法
public
class
AutoBundleProcessor
extends
AbstractProcessor
{
}在创建
AutoBundleProcessor
后,我们需要重写几个方法
@Override
public
synchronized
void
init(ProcessingEnvironment
ev)
{
}
在编译开始时首先会回调此方法,在这里,我们可以获取一些实例为后面做准备。在编译开始时首先会回调此方法,在这里,我们可以获取一些实例为后面做准备。
@Override
public
boolean
process(Set<?
extends
TypeElement>
set,
RoundEnvironment
rev)
{
}
在该方法中,我们能够获取需要的类、变量、注解等相关信息,后面我们会利用这些来生成代码在该方法中,我们能够获取需要的类、变量、注解等相关信息,后面我们会利用这些来生成代码
@Override
public
Set<String>
getSupportedAnnotationTypes()
{
}
该方法中我们可以指定具体需要处理哪些注解该方法中我们可以指定具体需要处理哪些注解接着我们需要使用到
Elements、
Filer、
Name、
TypeMirror
对象
Elements:对
Element
对象进行操作
Filer:文件操作接口,它可以创建
Java
文件
Name:表示类名、方法名
TypeMirror:表示数据类型。如
int、
String、以及自定义数据类型
下面我们可以获取被
@AutoBundle
注解元素的相关信息:
Set<?
extends
Element>
elementsAnnotatedWith
=
rev.getElementsAnnotatedWith(AutoBundle.class);
for
(Element
element
:
elementsAnnotatedWith)
{
if
(element.getKind()
==
ElementKind.FIELD)
{
VariableElement
variableElement
=
(VariableElement)
element;
TypeElement
typeElement
=
(TypeElement)
variableElement.getEnclosingElement();
//类名
String
className
=
typeElement.getSimpleName().toString();
//包名
String
packageName
=
mElementUtils.getPackageOf(typeElement).getQualifiedName().toString();
AutoBundle
autoBundle
=
variableElement.getAnnotation(AutoBundle.class);
//变量名
Name
simpleName
=
variableElement.getSimpleName();
//变量类型
TypeMirror
typeMirror
=
variableElement.asType();
}
}例如:
变量:
gender、
type:java.lang.String变量:
gender、
type:java.lang.String其他变量亦是如此。现在我们需要新建类来保存上面获取的值。这里我们新建
FieldHolder
来保存变量类型、变量名以及其他信息。
FieldHolder
public
class
FieldHolder
{
private
String
variableName;//变量名
private
TypeMirror
clazz;//字段类型(如:String)
private
String
packageName;//包名
private
boolean
addFlags;//是否是添加
activity
启动方式
private
boolean
exclude;//是否参与
intent、bundle
传值
private
boolean
closeFromActivity;//是否关闭当前
Activity
private
boolean
isBundle;//是否使用
Bundle
传值
private
boolean
isSerializable;//是否实现
Serializable
接口的类
private
boolean
isParcelable;//是否是自定义类实现
Parcelable
接口
private
boolean
isParcelableArray;//是否是自定义类
ParcelableArray
类型
private
boolean
isParcelableArrayList;//是否是自定义类
ParcelableArrayList
类型
}4、下面我们需要使用JavaPoet生成Java文件
A、TypeSpec.Builder
主要用于生成类,这里的类包括的范围比较广,可以是一个
class、一个
interface
等等。主要用于生成类,这里的类包括的范围比较广,可以是一个
class、一个
interface
等等。
B、MethodSpec.Builder
主要用于生成类主要用于生成类
C、FieldSpec.Builder
主要用于生成成员变量主要用于生成成员变量
D、JavaFile.Builder
主要用来生成Java文件主要用来生成Java文件
E、其他方法
生成成员变量以及变量的set方法
TypeSpec.Builder
typeClass
=
TypeSpec.classBuilder(clazzName
+
"AutoBundle");
for
(FieldHolder
fieldHolder
:
fieldHolders)
{
packageName
=
fieldHolder.getPackageName();
FieldSpec
builder
=
FieldSpec.builder(ClassName.get(fieldHolder.getClazz()),
fieldHolder.getVariableName(),
Modifier.PRIVATE).build();
typeClass.addField(builder);
MethodSpec.Builder
buildParamMethod
=
MethodSpec.methodBuilder(String.format("%s",
fieldHolder.getVariableName()));
buildParamMethod.addParameter(ClassName.get(fieldHolder.getClazz()),
fieldHolder.getVariableName());
buildParamMethod.addStatement(String.format("this.%s=%s",
fieldHolder.getVariableName(),
fieldHolder.getVariableName()));
buildParamMethod.addStatement(String.format("return
%s",
"this"));
buildParamMethod.addModifiers(Modifier.PUBLIC);
buildParamMethod.returns(ClassName.get(fieldHolder.getPackageName(),
clazzName
+
"AutoBundle"));
typeClass.addMethod(buildParamMethod.build());
}
生成的代码:
public
class
OtherActivityAutoBundle
{
private
String
name;
private
String
gender;
public
OtherActivityAutoBundle
name(String
name)
{
=
name;
return
this;
}
public
OtherActivityAutoBundle
gender(String
gender)
{
this.gender
=
gender;
return
this;
}
}
生成start方法
private
void
generateCommonStart(MethodSpec.Builder
builderMethod,
List<FieldHolder>
fieldHolders,
String
clazzName)
{
builderMethod.addStatement(String.format("Intent
intent
=
new
Intent(context,%s.class)",
clazzName));
/**
生成页面跳转方法
*/
for
(FieldHolder
fieldHolder
:
fieldHolders)
{
String
fieldType
=
fieldHolder.getClazz().toString();
if
("android.os.Bundle".equals(fieldType))
{
builderMethod.addStatement(String.format("Bundle
%s
=
new
Bundle()",
fieldHolder.getVariableName()));
builderMethod.addStatement(String.format("intent.putExtra(\"%s\",%s)",
fieldHolder.getVariableName(),
fieldHolder.getVariableName()));
mAutoBundleField
=
fieldHolder.getVariableName();
}
else
if
(fieldHolder.isBundle()
&&
String.class.getName().equals(fieldType))
{
builderMethod.addStatement(String.format("%s.putString(\"%s\",%s)",
mAutoBundleField,
fieldHolder.getVariableName(),
fieldHolder.getVariableName()));
}
else
if
((boolean.class.getName().equals(fieldType)
||
Boolean.class.getName().equals(fieldType))
&&
fieldHolder.isBundle())
{
builderMethod.addStatement(String.format("%s.putBoolean(\"%s\",%s)",
mAutoBundleField,
fieldHolder.getVariableName(),
fieldHolder.getVariableName()));
}
else
if
((byte.class.getName().equals(fieldType)
||
Byte.class.getName().equals(fieldType))
&&
fieldHolder.isBundle())
{
builderMethod.addStatement(String.format("%s.putByte(\"%s\",%s)",
mAutoBundleField,
fieldHolder.getVariableName(),
fieldHolder.getVariableName()));
}
else
if
((char.class.getName().equals(fieldType)
||
Character.class.getName().equals(fieldType))
&&
fieldHolder.isBundle())
{
builderMethod.addStatement(String.format("%s.putChar(\"%s\",%s)",
mAutoBundleField,
fieldHolder.getVariableName(),
fieldHolder.getVariableName()));
}
else
if
((short.class.getName().equals(fieldType)
||
Short.class.getName().equals(fieldType))
&&
fieldHolder.isBundle())
{
builderMethod.addStatement(String.format("%s.putShort(\"%s\",%s)",
mAutoBundleField,
fieldHolder.getVariableName(),
fieldHolder.getVariableName()));
}
else
if
((int.class.getName().equals(fieldType)
||
Integer.class.getName().equals(fieldType))
&&
fieldHolder.isBundle())
{
builderMethod.addStatement(String.format("%s.putInt(\"%s\",%s)",
mAutoBundleField,
fieldHolder.getVariableName(),
fieldHolder.getVariableName()));
}
else
if
((long.class.getName().equals(fieldType)
||
Long.class.getName().equals(fieldType))
&&
fieldHolder.isBundle())
{
builderMethod.addStatement(String.format("%s.putLong(\"%s\",%s)",
mAutoBundleField,
fieldHolder.getVariableName(),
fieldHolder.getVariableName()));
}
else
if
((float.class.getName().equals(fieldType)
||
Float.class.getName().equals(fieldType))
&&
fieldHolder.isBundle())
{
builderMethod.addStatement(String.format("%s.putFloat(\"%s\",%s)",
mAutoBundleField,
fieldHolder.getVariableName(),
fieldHolder.getVariableName()));
}
else
if
((double.class.getName().equals(fieldType)
||
Double.class.getName().equals(fieldType))
&&
fieldHolder.isBundle())
{
builderMethod.addStatement(String.format("%s.putDouble(\"%s\",%s)",
mAutoBundleField,
fieldHolder.getVariableName(),
fieldHolder.getVariableName()));
}
}
结果
public
void
start(Context
context)
{
Intent
intent
=
new
Intent(context,
OtherActivity.class);
intent.putExtra("id",
id);
intent.putExtra("name",
name);
intent.putExtra("is",
is);
intent.putExtra("mByte",
mByte);
intent.putExtra("b",
b);
intent.putExtra("mShort",
mShort);
intent.putExtra("mLong",
mLong);
intent.putExtra("mFloat",
mFloat);
intent.putExtra("mDouble",
mDouble);
context.startActivity(intent);
}
生成bindIntentData
for
(FieldHolder
fieldHolder
:
fieldHolders)
{
packageName
=
fieldHolder.getPackageName();
TypeMirror
clazz
=
fieldHolder.getClazz();
String
fieldType
=
clazz.toString();
if
((boolean.class.getName().equals(fieldType)
||
Boolean.class.getName().equals(fieldType))
&&
!fieldHolder.isBundle()&&!fieldHolder.isExclude())
{
bindIntentMethod.addStatement(String.format("target.%s
=
intent.getBooleanExtra(\"%s\",false)",
fieldHolder.getVariableName(),
fieldHolder.getVariableName()));
}
else
if
((byte.class.getName().equals(fieldType)
||
Byte.class.getName().equals(fieldType))
&&
!fieldHolder.isBundle())
{
bindIntentMethod.addStatement(String.format("target.%s
=
intent.getByteExtra(\"%s\",(byte)0)",
fieldHolder.getVariableName(),
fieldHolder.getVariableName()));
}
else
if
((char.class.getName().equals(fieldType)
||
Character.class.getName().equals(fieldType))
&&
!fieldHolder.isBundle())
{
bindIntentMethod.addStatement(String.format("target.%s
=
intent.getCharExtra(\"%s\",(char)0)",
fieldHolder.getVariableName(),
fieldHolder.getVariableName()));
}
else
if
((short.class.getName().equals(fieldType)
||
Short.class.getName().equals(fieldType))
&&
!fieldHolder.isBundle())
{
bindIntentMethod.addStatement(String.format("target.%s
=
intent.getShortExtra(\"%s\",(short)0)",
fieldHolder.getVariableName(),
fieldHolder.getVariableName()));
}
else
if
((int.class.getName().equals(fieldType)
||
Integer.class.getName().equals(fieldType))
&&
!fieldHolder.isBundle()&&!fieldHolder.isExclude())
{
bindIntentMethod.addStatement(String.format("target.%s=intent.getIntExtra(\"%s\",0)",
fieldHolder.getVariableName(),
fieldHolder.getVariableName()));
}
else
if
((long.class.getName().equals(fieldType)
||
Long.class.getName().equals(fieldType))
&&
!fieldHolder.isBundle())
{
bindIntentMethod.addStatement(String.format("target.%s=intent.getLongExtra(\"%s\",0)",
fieldHolder.getVariableName(),
fieldHolder.getVariableName()));
}
else
if
((float.class.getName().equals(fieldType)
||
Float.class.getName().equals(fieldType))
&&
!fieldHolder.isBundle())
{
bindIntentMethod.addStatement(String.format("target.%s=intent.getFloatExtra(\"%s\",0)",
fieldHolder.getVariableName(),
fieldHolder.getVariableName()));
}
else
if
((double.class.getName().equals(fieldType)
||
Double.class.getName().equals(fieldType))
&&
!fieldHolder.isBundle())
{
bindIntentMethod.addStatement(String.format("target.%s=intent.getDoubleExtra(\"%s\",0)",
fieldHolder.getVariableName(),
fieldHolder.getVariableName()));
}
}
生成的结果
public
void
bindIntentData(OtherActivity
target,
Intent
intent)
{
target.id
=
intent.getIntExtra("id",
0);
=
intent.getStringExtra("name");
target.is
=
intent.getBooleanExtra("is",
false);
target.mByte
=
intent.getByteExtra("mByte",
(byte)
0);
target.b
=
intent.getCharExtra("b",
(char)
0);
target.mShort
=
intent.getShortExtra("mShort",
(short)
0);
target.mLong
=
intent.getLongExtra("mLong",
0);
target.mFloat
=
intent.getFloatExtra("mFloat",
0);
target.mDouble
=
intent.getDoubleExtra("mDouble",
0);
}
最后将生成好的Java代码写入文件
//与目标
Class
放在同一个包下,解决
Class
属性的可访问性
JavaFile
javaFile
=
JavaFile.builder(packageName,
typeClass.build())
.build();
try
{
//生成
class
文件
javaFile.writeTo(mFiler);
}
catch
(IOException
e)
{
e.printStackTrace();
}生成的文件在
app/build/generated/ap_generated_sources/debug/out/包名/xxx
最后生成的代码:
/**
*
This
codes
are
generated
automatically.
Do
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年个性化住宅装修服务协议范本
- 2024年度旅游包车服务协议范本
- 2024年股东合伙协议样本
- 2024-2025学年北京市海淀区首都师大附中永定分校九年级(上)期中数学试卷
- 2024年电子行业保密协议范本
- 2024年专业监控设备安装协议模板
- 2024年商业合作盈利共享协议
- 2024年度水产养殖饲料订货供应协议
- 2024年住宅建筑质量保障协议
- 血管解剖课件教学课件
- 八年级道德与法治上册 第一单元 走进社会生活 单元复习课件
- 设计师会议管理制度
- 三年级上册数学说课稿《5.笔算多位数乘一位数(连续进位)》人教新课标
- 行贿受贿检讨书
- 人教版《劳动教育》六上 劳动项目二《晾晒被子》教学设计
- (正式版)QC∕T 1208-2024 燃料电池发动机用氢气循环泵
- 中外合作办学规划方案
- 医学美容技术专业《中医美容技术》课程标准
- CJJ207-2013 城镇供水管网运行、维护及安全技术规程
- 六年级道德与法治期末测试卷加答案(易错题)
- 三位数除以两位数300题-整除-有标准答案
评论
0/150
提交评论