通过注解和反射获取Activity Intent里的数据
实际开发中,我们经常需要在不同页面之间传递数据。我们一般使用在页面之间传递数据。使用Intent put各种类型的数据,然后在另一个页面接收。如果接收的数据量不多还好办,可是多了,页面就会出现很多intent.getIntExtra()、intent.getStringExtra()这样的代码,不美观,而且容易赋值出错,导致一直在排查。或者赋错了值,导致业务出错,又不能及时察觉。如果使用注解和反射解决赋值的问题,就会避免这些问题了。
首先,我们需要定义一个注解。由于是作用于成员变量的,所以@Target值应该为ElementType.FIELD。要实现在运行时获取到Intent传来的值并且赋值的目的,则@Retention必须为RetentionPolicy.RUNTIME。而且Intent传值时,使用的key为String类型,所以注解里的方法返回值应该是String类型。自定义注解如下:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
String value() default "";
}
然后我们需要定义获取到传递的值,并且赋值的工具类。这里我们仅仅以Activity为例子:
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Parcelable;
import android.text.TextUtils;
import java.lang.reflect.Field;
import java.util.Arrays;
public class IntentUtil {
public static void initIntent(Activity activity) {
Intent intent = activity.getIntent();
Bundle extras = intent.getExtras();
if (extras == null) {
return;
}
Class<? extends Activity> cls = activity.getClass();
//获取此类的所有成员
Field[] fields = cls.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Autowired.class)) {
Autowired autowired = field.getAnnotation(Autowired.class);
//是否使用注解给定了别名
boolean hasValue = TextUtils.isEmpty(autowired.value());
//如果别名不为空,使用别名获取key
String key = hasValue ? field.getName() : autowired.value();
//判断extras是否有当前key
if (extras.containsKey(key)) {
Object object = extras.get(key);
//Parcelable数组类型不能直接设置,需要转化,其他的数组类型都可以直接设置
Class<?> componentType = field.getType().getComponentType();
if (field.getType().isArray() && Parcelable.class.isAssignableFrom(componentType)) {
Object[] objs = (Object[]) object;
Object[] objects = Arrays.copyOf(objs, objs.length, (Class<? extends Object[]>) field.getType());
object = objects;
}
field.setAccessible(true);
try {
/**
* 当前的属性字段都是成员变量,所以字段重新设置给activity对象,
* 如果不是对象的字段,而是对象对应的类的属性,即static的属性,
* 则需要传入null,即field.set(null, object);
*/
field.set(activity, object);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
}
现在注解和工具类都定义好了,我们还需要定义几个常用的实体类。如下:
/**
* 实现序列化接口Parcelable
*/
public class UserParcelable implements Parcelable {
String name;
public UserParcelable(String name) {
this.name = name;
}
protected UserParcelable(Parcel in) {
name = in.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<UserParcelable> CREATOR = new Creator<UserParcelable>() {
@Override
public UserParcelable createFromParcel(Parcel in) {
return new UserParcelable(in);
}
@Override
public UserParcelable[] newArray(int size) {
return new UserParcelable[size];
}
};
@Override
public String toString() {
return "UserParcelable{" +
"name='" + name + '\'' +
'}';
}
}
public class UserSerializable implements Serializable {
String name;
public UserSerializable() {
}
public UserSerializable(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "UserSerializable{" +
"name='" + name + '\'' +
'}';
}
}
实体类也定义好了,我们来试试效果。先定义两个Activity和两个xml文件,其中OneActivity负责传值,TwoActivity负责展示:
OneActivity:
public class OneActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn_start;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_one);
btn_start = findViewById(R.id.btn_start);
btn_start.setOnClickListener(this);
}
@Override
public void onClick(View v) {
ArrayList<UserParcelable> userParcelableArrayList = new ArrayList<>();
userParcelableArrayList.add(new UserParcelable("博客-第一代码"));
Intent intent = new Intent(this, SecondActivity.class);
intent.putExtra("name", "第一代码");
intent.putExtra("intArray", new int[]{10, 20, 30, 40, 50});
intent.putExtra("strArray", new String[]{"diyidaima.com", "博客网站"});
intent.putExtra("userParcelable", new UserParcelable("序列化数据"));
intent.putExtra("userParcelableArray", new UserParcelable[]{new UserParcelable("序列化数组数据1")});
intent.putExtra("users", new UserSerializable[]{new UserSerializable("序列化数组数据2")});
intent.putParcelableArrayListExtra("userParcelableArrayList",userParcelableArrayList);
startActivity(intent);
}
}
OneActivity:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".OneActivity">
<Button
android:id="@+id/btn_start"
android:layout_width="0dp"
android:layout_height="45dp"
android:gravity="center"
android:text="携带数据跳转到SecondActivity"
android:layout_marginHorizontal="16dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
SecondActivity:
public class SecondActivity extends AppCompatActivity {
@Autowired
String name;
@Autowired("intArray")
int[] intArr;
@Autowired("strArray")
String[] strArr;
@Autowired
UserParcelable userParcelable;
@Autowired
UserParcelable[] userParcelableArray;
@Autowired("users")
UserSerializable[] userSerializables;
@Autowired
List<UserParcelable> userParcelableArrayList;
TextView tv_result;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
IntentUtil.initIntent(this);
tv_result = findViewById(R.id.tv_result);
tv_result.setText("接收到的数据:\n\n" + toString());
}
@Override
public String toString() {
return "SecondActivity { " + "\n\n" +
"name = '" + name + '\'' + ", \n\n" +
"intArr = " + Arrays.toString(intArr) + ", \n\n" +
"strArr = " + Arrays.toString(strArr) + ", \n\n" +
"userParcelable = " + userParcelable + ", \n\n" +
"userParcelableArray = " + Arrays.toString(userParcelableArray) + ", \n\n" +
"userSerializables = " + Arrays.toString(userSerializables) + ", \n\n" +
"userParcelableArrayList = " + userParcelableArrayList + "\n\n" +
'}';
}
}
activity_second:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SecondActivity">
<TextView
android:id="@+id/tv_result"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_margin="16dp"
android:textColor="@android:color/black"
android:textSize="14sp"
android:text="接收到的数据:"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
测试结果如下图:
至此完成!!!
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。




