一、前言
註解可以理解成標記,打標籤。單獨的一個註解是沒用的,需要搭配使用,例如搭配反射等等。我們需要通過使用註解上的值來做相應的操作。
二、自定義一個註解
package com.example.myapplication;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定義一個註解
* InjectAnnotation
* 註解可以理解成標記,打標籤,
* 1、設置Retention註解,表示定義註解的級別、也可以理解爲註解的生命週期
* (1)RetentionPolicy.SOURCE源碼上
* 表示註解存在源碼中,當通過JAVAC編譯成字節碼之後,註解便不存在。此類型註解可以用在我們的註解處理中
* 因爲註解處理器的方法執行在編譯器,我們可以在註解處理器的方法執行時候獲取我們的註解內容,做相應的一些操作,例如生成一些我們需要的輔助類
* 比如Arouter框架。也可以用於源代碼的檢查。例如當我們的方法希望傳遞指定的類型的時候,可以使用註解來限制。
* (2)RetentionPolicy.CLASS字節碼上
* 此類型註解表示註解在字節碼中存在,即源碼編譯成字節碼,註解一直存在。可以用在字節碼增強、插裝的一些實現。
* 也就是在字節碼中獲取註解內容,針對原有字節碼進行一些修改,而達到字節碼增強的效果。例如我們的熱修復
* <p>
* (3)RetentionPolicy.RUNTIME 運行期間,也叫運行行註解
* 運行時註解,也就是從編譯到運行,註解一直存在,在程序運行的時候,我們可以使用我們的註解。例如:我們程序運行的時候,我們可以通過獲取註解+反射來實現一些功能,例如
* 實現view.findId
* <p>
* <p>
* 2、設置註解作用目標的對象
* 常用的有
* (1)TYPE 作用在類上
* (2)FIELD 變量上
* (3)METHOD 方法上
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ValueAnnotation {
String value();
DataType dataType();
}
自定義註解使用@interface關鍵字,並在註解上使用@Retention註解和@Target註解
- 1、設置Retention註解,表示定義註解的級別、也可以理解爲註解的生命週期
(1)RetentionPolicy.SOURCE源碼上
表示註解存在源碼中,當通過JAVAC編譯成字節碼之後,註解便不存在。此類型註解可以用在我們的註解處理中
因爲註解處理器的方法執行在編譯器,我們可以在註解處理器的方法執行時候獲取我們的註解內容,做相應的一些操作,例如生成一些我們需要的輔助類。比如Aruter框架。也可以用於源代碼的檢查。例如當我們的方法希望傳遞指定的類型的時候,可以使用註解來限制。
(2)RetentionPolicy.CLASS字節碼上
此類型註解表示註解在字節碼中存在,即源碼編譯成字節碼,註解一直存在。可以用在字節碼增強、插裝的一些實現。 也就是在字節碼中獲取註解內容,針對原有字節碼進行一些修改,而達到字節碼增強的效果。例如我們的熱修復。
(3)RetentionPolicy.RUNTIME 運行期間上的註解
也叫運行時註解,運行時註解,也就是從編譯到運行,註解一直存在,在程序運行的時候,我們可以使用我們的註解。例如:我們程序運行的時候,我們可以通過獲取註解+反射來實現一些功能,例如: 實現findById
- 2、設置註解作用目標的對象(Target註解)
常用的有:
(1)TYPE 作用在類上
(2)FIELD 變量上
(3)METHOD 方法上 - 3、設置註解的值
例如代碼中的,value和dataType,註解值可以有多個
三、註解結合反射實現Android中Activity頁面跳轉Intent值的獲取
1、自定義一個註解,也就是上面的註解
2、創建一個工具類
主要功能就是通過反射獲取Activity中的成員屬性,並且是獲取帶有我們自定義註解的屬性成員。然後獲取註解上的值,註解上設置了兩個值:字符串參數名和枚舉類型的數據類型。
根據數據類型和參數名,通過activity.getIntent()來獲取Intent上的值,拿到值之後,給成員賦值即可
package com.example.myapplication;
import java.lang.reflect.Field;
import androidx.appcompat.app.AppCompatActivity;
public class InjectUtils {
public static void init(AppCompatActivity activity) {
//1、通過actibity對象獲取class對象
Class<? extends AppCompatActivity> activityClass = activity.getClass();
//2.獲取該類的所有成員
Field[] fields = activityClass.getDeclaredFields();
//3.遍歷獲取:有打上ValueAnnotation註解的成員
for (int i = 0; i < fields.length; i++) {
if (fields[i].isAnnotationPresent(ValueAnnotation.class)) {
try {
//4、給成員設置訪問權限、
fields[i].setAccessible(true);//也就是當成員是private的時候,允許訪問
//5、獲取成員上的註解的值
ValueAnnotation valueAnnotations = fields[i].getAnnotation(ValueAnnotation.class);
String value = valueAnnotations.value();
DataType dataType = valueAnnotations.dataType();
//6、判斷數據類型,設置值
if (dataType == DataType.IntegerData) {
Integer result = activity.getIntent().getIntExtra(value, 0);
fields[i].set(activity, result);
}
if (dataType == DataType.StringData) {
String result = activity.getIntent().getStringExtra(value);
fields[i].set(activity, result);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
在Activity上使用
package com.example.myapplication;
import android.os.Bundle;
import android.util.Log;
import java.lang.reflect.Type;
import androidx.appcompat.app.AppCompatActivity;
public class ResultActivity extends AppCompatActivity {
@ValueAnnotation(value = "result", dataType = DataType.StringData)
private String result;
@ValueAnnotation(value = "age", dataType = DataType.IntegerData)
private Integer age;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InjectUtils.init(this);
Log.e("ResultActivity", "result = " + result);
Log.e("ResultActivity", "age = " + age);
// //通過反射獲取泛型類型
// //通過匿名內部類來實現,獲取泛型的類型
// TypeClass<String> typeClass = new TypeClass<String>() {
// };
// Log.e("ResultActivity", "getType = "+typeClass.getType());
}
}