正常我們從一個activity
跳入另一個界面時候,如果需要攜帶參數。則代碼如下
public static void startActivity(Activity activity,UserChange userChange){
Intent intent = new Intent(activity,UserChangeActivity.class);
intent.putExtra(DATA_KEY,userChange);
activity.startActivity(intent);
}
然後跳轉的activity
裏面獲取數據
UserChange userChange;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
userChange = (UserChange) getIntent().getSerializableExtra(DATA_KEY);
}
記得以前看ARouter
源碼的時候。要跳轉的activity
只要在字段上面加個註解。就能自動解析傳遞過來的參數。想着實現起來也不難,於是手動擼起來。
跳轉的方法封裝先,我們定義了一個通用的key。封裝了跳轉時要帶參數的方法。這樣跳轉就很簡單了,只要把要跳轉的class和數據傳進去就可以了。
public final static String INTENT_DATA_KEY="INTENT_DATA_KEY";
/**
* 跳轉到Activity
*
* @param clazz Activity類
*/
protected void startActivity(Class clazz,Object data) {
Bundle bundle = new Bundle();
putData(bundle,INTENT_DATA_KEY,data);
startActivityForResult(clazz, -1, bundle);
}
private void putData(Bundle bundle,String key,Object data){
if (data instanceof Integer){
bundle.putInt(key,(Integer) data);
}else if (data instanceof String){
bundle.putString(key,(String) data);
}else if(data instanceof Serializable){
bundle.putSerializable(key,(Serializable) data);
}
}
接收的地方更簡單了,只要在屬性上面添加一個枚舉修飾
@IntentData
UserChange userChange;
當然如果多個參數,則屬性的枚舉對應的key
要和這裏的map
裏面的key
一一對應
/**
* 跳轉到Activity
*
* @param clazz Activity類
*/
protected void startActivity(Class clazz,Map<String,Object> datas) {
Bundle bundle = new Bundle();
for (Map.Entry<String, Object> entry : datas.entrySet()) {
putData(bundle,entry.getKey(),entry.getValue());
}
startActivityForResult(clazz, -1, bundle);
}
枚舉,很簡單.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface IntentData {
String key() default INTENT_DATA_KEY;
}
然後就是在onCreate
裏面找到枚舉的字段,解析,賦值
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
resolveIntentData();
}
遍歷屬性,找到帶IntentData枚舉的屬性
void resolveIntentData(){
Field[] fields= getClass().getDeclaredFields();
for (int i=0;i<fields.length;i++){
Field f = fields[i];
IntentData intentData=f.getAnnotation(IntentData.class);
//如果屬性上面有IntentData修飾
if (intentData!=null) {
setIntentData(intentData,f);
}
}
}
一個一個找到後賦值。這裏有個陷阱。Serializable
判斷一定要放在最後,因爲其他的類型都實現了Serializeable
接口,如果判斷放在最前面,則總是會符合條件。
private void setIntentData(IntentData intentData,Field f){
if (intentData!=null){
Intent intent = getIntent();
//獲取註解字段的類型
Class clazz=f.getType();
Object o = null;
String key = intentData.key();
//根據字段的類型獲取
if (Integer.class==clazz||int.class==clazz){
o = intent.getIntExtra(key,0);
}else if (String.class==clazz){
o = intent.getStringExtra(key);
} else if (Boolean.class==clazz||boolean.class==clazz){
o = intent.getBooleanExtra(key,false);
}else if (Serializable.class.isAssignableFrom(clazz)){
o = intent.getSerializableExtra(key);
}
//如果獲取到,賦值
if (o!=null) {
ReflectUtil.setField(this, f.getName(), o);
}
}
}
賦值的操作就比較簡單。當然也可以像ButterKnife
那樣。在編譯期自動生成代碼處理。只不過那樣難度大些。
public static Field getField(Class<?> clazz, String fieldName) {
Field field = null;
try {
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
} catch (NoSuchFieldException var4) {
var4.printStackTrace();
}
return field;
}
public static void setField(Object obj, String fieldName, Object value) {
Field field = getField(obj.getClass(), fieldName);
if (field != null) {
try {
field.set(obj, value);
} catch (IllegalAccessException var5) {
var5.printStackTrace();
}
}
}
把上述代碼封裝在BaseActivity
裏面,則後面跳轉界面傳遞參數就直接調用下面封裝方法。
/**
* 跳轉到Activity
*
* @param clazz Activity類
*/
protected void startActivity(Class clazz,Object data) {
Bundle bundle = new Bundle();
putData(bundle,INTENT_DATA_KEY,data);
startActivityForResult(clazz, -1, bundle);
}