先写一个注解类:
public @interface InjectView {
@IdRes int value();
}
它是使用@interface修饰符,单纯一个注解类没啥用,哪怕是你给这个注解作用到一个类上也没什么用,什么时候有用就要看这个注解类执行的时机:
1、@Retention(RetentionPolicy.SOURCE) 此处是源码阶段也就是javac编译时 应用场景如:APT
2、@Retention(RetentionPolicy.CLASS) 此处是字节码阶段 应用场景如:插装
3、@Retention(RetentionPolicy.RUNTIME) 此处是运行时态 应用场景如:ButterKnife
自己实现一个类似ButterKnife的功能,需要用到反射
一、注解类
//@Retention(RetentionPolicy.SOURCE)//此处是源码阶段也就是javac编译时 应用场景如:APT
//@Retention(RetentionPolicy.CLASS)//此处是字节码阶段 应用场景如:插装
@Retention(RetentionPolicy.RUNTIME)//标记注解在哪个阶段执行,此处是运行时态 应用场景如:ButterKnife
@Target(ElementType.FIELD) //标记注解的目标位置,注解可以在类上、方法上、成员变量上 此处我们作用在成员变量上
public @interface InjectView {
//标记value类型是资源类型,也就是使用过程中,注解的值是R.id.XXX
@IdRes int value();
}
二、注解工具
public class InjectViewUtils {
public static void injectView(Activity activity){
Class<? extends Activity> activityClass = activity.getClass();
// activityClass.getFields();//获得某个类的所有的公共(public)的字段,包括父类中的字段。
Field[] declaredFields = activityClass.getDeclaredFields();//获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的申明字段
for (Field field : declaredFields) {
//如果是被InjectView注解的声明
if(field.isAnnotationPresent(InjectView.class)){
//获取这个注解的类
InjectView injectView = field.getAnnotation(InjectView.class);
//获取注解里面的值,就是R.id.XXX对应的值
int resId = injectView.value();
View view = activity.findViewById(resId);
field.setAccessible(true);
try {
field.set(activity,view);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
三、在activity中调用
public class MainActivity extends AppCompatActivity {
@InjectView(R.id.tv)
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InjectViewUtils.injectView(this);
tv.setText("inject view success!");
}
}
运行成功!
这样就实现了一个类似ButterKnife的功能!
接下来再实现一个Intent传值通过注解的方式获取传值:
依然是需要一个注解类:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface InjectIntent {
String value() default "";
}
注解工具:
public class InjectIntentUtils {
public static void injectIntent(Activity activity){
Class<? extends Activity> activityClass = activity.getClass();
Intent intent = activity.getIntent();
Bundle extras = intent.getExtras();
if(extras == null){
return;
}
//反射获取类里面的所有成员变量
Field[] declaredFields = activityClass.getDeclaredFields();
for (Field field : declaredFields) {
if(field.isAnnotationPresent(InjectIntent.class)){
InjectIntent injectIntent = field.getAnnotation(InjectIntent.class);
String key = injectIntent.value();
if(TextUtils.isEmpty(key)){
key = field.getName();
}
if(extras.containsKey(key)){
Object obj = extras.get(key);
//如果传的参数是一个数组类型的
if(field.getType().isArray()){
//获取数组类型的type
Class<?> componentType = field.getType().getComponentType();
if(componentType == null){
return;
}
//如果该数组类型是Parcelable的
if(Parcelable.class.isAssignableFrom(componentType)){
Object[] objs = (Object[]) obj;
Object[] objects = Arrays.copyOf(objs,objs.length, (Class<? extends Object[]>) field.getType());
obj = objects;
}
}
field.setAccessible(true);
try {
field.set(activity,obj);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
}
从一个activity跳转到另一个activity获取intent传值
public class MainActivity extends AppCompatActivity {
@InjectView(R.id.tv)
private TextView tv;
private String name;
private ArrayList<UserInfo> userInfoList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InjectViewUtils.injectView(this);
tv.setText("inject view success!");
userInfoList.add(new UserInfo("测试1"));
userInfoList.add(new UserInfo("测试2"));
name = "hello name";
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,IntentActivity.class);
intent.putExtra("name",name);
intent.putParcelableArrayListExtra("userInfoList",userInfoList);
intent.putExtra("testArray",new UserInfo[]{new UserInfo("hello")});
startActivity(intent);
}
});
}
}
public class IntentActivity extends AppCompatActivity {
@InjectView(R.id.tv)
private TextView tv;
@InjectIntent("name")
private String name;
@InjectIntent
private ArrayList<UserInfo> userInfoList;
@InjectIntent
private UserInfo[] testArray;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InjectViewUtils.injectView(this);
InjectIntentUtils.injectIntent(this);
tv.setText(name);
for (UserInfo userInfo : userInfoList) {
Log.e("UserInfo:",userInfo.getName());
}
for (UserInfo userInfo : testArray) {
Log.e("UserInfo:",userInfo.getName());
}
}
}
public class UserInfo implements Parcelable {
private String name;
public UserInfo(String name) {
this.name = name;
}
private UserInfo(Parcel in) {
this.name = in.readString();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
}
public static final Creator<UserInfo> CREATOR = new Creator<UserInfo>() {
@Override
public UserInfo createFromParcel(Parcel source) {
return new UserInfo(source);
}
@Override
public UserInfo[] newArray(int size) {
return new UserInfo[size];
}
};
}