通过注解和反射获取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>
测试结果如下图:
至此完成!!!
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。