亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

3000行代碼怎樣簡化成300行?來,一文來教你!

發布時間:2020-08-04 15:03:02 來源:ITPUB博客 閱讀:172 作者:yilian 欄目:移動開發

前言

APT(Annotation Processor Tool)是用來處理注解的,即注解處理器。 APT 在編譯器會掃描處理源代碼中的注解,我們可以使用這些注解,然后利用  APT自動生成  Java代碼,減少模板代碼,提升編碼效率,使源碼更加簡潔,可讀性更高。

1、具體場景

下面我將會以項目中常見的 intent 頁面跳轉為例,給大家演示一下,如何自動生成  intent代碼,以及對 getIntent的參數自動賦值。

要實現上面這個功能我們需要了解  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());

2、搭建 APT 項目

a、創建一個 Java Library,并創建注解類
例如:

  @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、再創建一個 Java Library,并將上一步 Java Library 添加進來

此時,我們還需要在該 Library 中創建  resources 文件夾;接著在  resources 中創建  META-INF 和  services 兩個文件夾;然后在  services 中創建一個名為  javax.annotation.processing.Processor 的文件。最后在該文件中寫入我們注解處理器的全路徑。

這里我們也可以使用自動化工具  implementation 'com.google.auto.service:auto-service:1.0-rc2' 感興趣的去搜一下具體用法

3000行代碼怎樣簡化成300行?來,一文來教你!

3、創建自己的處理類,繼承 AbstractProcessor

  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、  FilerNameTypeMirror 對象
Elements:對  Element 對象進行操作
Filer:文件操作接口,它可以創建  Java 文件
Name:表示類名、方法名
TypeMirror:表示數據類型。如  intString、以及自定義數據類型
下面我們可以獲取被  @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();
        }
   }

例如:

變量: gendertype: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 文件

簡單介紹下需要用到的 API

A、TypeSpec.Builder

主要用于生成類,這里的類包括的范圍比較廣,可以是一個  class、一個  interface 等等。

方法 功能
classBuilder 生成類
interfaceBuilder 生成接口

B、MethodSpec.Builder

主要用于生成類

方法 功能
constructBuilder 生成構造方法
methodBuilder 生成成員方法

C、FieldSpec.Builder

主要用于生成成員變量

方法 功能
builder 生成一個成員變量

D、JavaFile.Builder

主要用來生成 Java 文件

方法 功能
builder 生成一個 JavaFile 對象
writeTo 將數據寫到 Java 文件中

E、其他方法

方法 功能 描述
addModifier 添加修飾符 比如:public、private、static 等等
addParameter 添加參數 向方法中添加參數。例:addParameter(ClassName.get("包名"),"類名")
addStatement 添加陳述 直接添加代碼。例:addStatement("return this")
addCode 添加代碼語句 直接添加代碼,自動幫你導入需要的包,并在末尾自動添加分號
returns 添加返回值 為方法添加返回值。例:returns(void.class)
addMethod 添加方法 將生成的方法添加到類中。例:addMethod(customMethod.build())
addField 添加變量 將生成的變量添加到類中。例:addField(customField.build())

生成成員變量以及變量的 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) {        this.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);
          target.name = 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

3000行代碼怎樣簡化成300行?來,一文來教你!

最后生成的代碼:

  /**
   * This codes are generated automatically. Do not modify! */
  public class ThirdActivityAutoBundle {    private int no;    private String address;    private boolean isChoose;    public ThirdActivityAutoBundle no(int no) {      this.no=no;      return this;
    }    public ThirdActivityAutoBundle address(String address) {      this.address=address;      return this;
    }    public ThirdActivityAutoBundle isChoose(boolean isChoose) {      this.isChoose=isChoose;      return this;
    }    public void start(Context context) {
      Intent intent = new Intent(context,ThirdActivity.class);
      intent.putExtra("no",no);
      intent.putExtra("address",address);
      intent.putExtra("isChoose",isChoose);
      context.startActivity(intent);
    }    public void startForResult(Context context, Integer requestCode) {
      Intent intent = new Intent(context,ThirdActivity.class);
      intent.putExtra("no",no);
      intent.putExtra("address",address);
      intent.putExtra("isChoose",isChoose);
      ((android.app.Activity)context).startActivityForResult(intent,requestCode);
    }    public void bindIntentData(ThirdActivity target, Intent intent) {
      target.no=intent.getIntExtra("no",0);
      target.address=intent.getStringExtra("address");
      target.isChoose = intent.getBooleanExtra("isChoose",false);
    }
  }
總結

好了,到這里就全部結束了,大家可以發揮想象力添加自己想要的功能。
喜歡的話,點個贊唄

作為一個程序員,要學的東西有很多,而學到的知識點,都是錢(因為技術人員大部分情況是根據你的能力來定級、來發薪水的),技多不壓身。

為了很好的生活,我們要多多學習,增加我們手里的金錢。尤其經歷了這一疫情,我深深的感受到金錢的重要,所以,我們一定不能停下學習的腳步!

附上我的Android核心技術學習大綱,獲取相關內容來GitHub: https://github.com/Meng997998/AndroidJX
vx:xx13414521

3000行代碼怎樣簡化成300行?來,一文來教你!
向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

四会市| 兴和县| 蓬莱市| 丹凤县| 神池县| 林周县| 阳朔县| 新乡县| 东山县| 东乌| 怀集县| 肃宁县| 玉林市| 绥芬河市| 梁河县| 驻马店市| 莎车县| 乡宁县| 荣成市| 昭平县| 广元市| 田林县| 广东省| 邹城市| 平塘县| 灵宝市| 郧西县| 临海市| 望都县| 宁南县| 厦门市| 清水河县| 武夷山市| 新昌县| 玛多县| 浦县| 额济纳旗| 石阡县| 张家港市| 屯门区| 蕲春县|