【移动应用开发技术】3000行代码怎样简化成300行?来一文来教你_第1页
【移动应用开发技术】3000行代码怎样简化成300行?来一文来教你_第2页
【移动应用开发技术】3000行代码怎样简化成300行?来一文来教你_第3页
【移动应用开发技术】3000行代码怎样简化成300行?来一文来教你_第4页
【移动应用开发技术】3000行代码怎样简化成300行?来一文来教你_第5页
已阅读5页,还剩10页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

【移动应用开发技术】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. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论