普通写Intent的方法和缺陷
- 普通Activity A要调用起Activity B页面会这么写:
Activity A:
Intent intent = new Intent(A.this, B.class);
intent.putExtra("is_index", message);
startActivity(intent);
Activity B:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
String is_index = getIntent().getExtras().getString("is_index");
...
}
- 上面的写法是大多数Intent写法,在发起方创建intent。但这种写法在代码量大大增加的时候会出现一个问题。当Activity B在各种地方都会被调用起的时候,并且会传入各种各样不同的extra字段时,会发现很混乱,哪些发起方使用了哪些extra字段,每个字段什么意思,哪些是必须的等等问题。最终造成B代码可读性变差,让以后想要调用起B的页面也不清楚需要传入哪些extra。
优化写Intent
- 同样是Activity A要调用起Activity B页面的例子:
Activity A:
Intent intent = B.newIndexIntent(this, message);
startActivity(intent);
Activity B:
private final static String IS_INDEX = "is_index";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
String is_index = getIntent().getExtras().getString(IS_INDEX);
...
}
...
/**
* 创建intent
* is_index 是否是首页跳转过来的
*/
public static Intent newIndexIntent(Context context, String message) {
Intent newIntent = new Intent(context, b.class);
newIntent.putExtra(IS_INDEX, message);
return newIntent;
}
- 用上面的方法可以保证所有extra全部定义在被调用起Activity的内部,对外不可见,并可以对每个extra有详细的注释(是否必须、在什么地方调用等)。
思考
- 跳转的时候是否可以直接写为 B.newIndexIntent(this,text),因为 发起启动的不是界面,而是上下文对象。是否可以直接做B.class里面封装一个启动方法,里面接受几个参数,然后用传过来的context启动。但有一些特殊情况,如:启动时为startActivityForResult,result的值最好还是放在启动的类里定义等。
附录
- Intent中的各种FLAG
Intent intent = new Intent(this,xxx.class);
//如果activity在task存在,拿到最顶端,不会启动新的Activity
intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
//如果activity在task存在,将Activity之上的所有Activity结束掉
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
//默认的跳转类型,将Activity放到一个新的Task中
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//如果Activity已经运行到了Task,再次跳转不会在运行这个Activity
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
网上有关于Intent flag和taskAffinity的实验结果, 我们来看下相关结论:
FLAG_ACTIVITY_NEW_TASK并不像官方文档所说的等同与singleTask.
在没有任何其他flag组合和taskAffinity设置的情况下, 同一应用内FLAG_ACTIVITY_NEW_TASK启动另外一个Activity, 不会在新的Task中创建实例, 也不会有实例复用.
FLAG_ACTIVITY_SINGLE_TOP作用等同与singleTop, 当Task的top Activity是该Activity时, Activity复用.
FLAG_ACTIVITY_CLEAR_TOP会clear top, 也就是说如果Task中有ABCD, 在D中启动B, 会clear掉B以上的CD. CD销毁.
注意, FLAG_ACTIVITY_CLEAR_TOP并不意味着重用, 默认Activity为standard模式的话, 只是会clear其top的其他Activity实例, 该Activity并不会重用, 而是也会销毁, 然后创建一个新的该Activity实例来响应此Intent.
在没有设置taskAffinity的情况下, 同一应用内FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_CLEAR_TOP组合启动另外一个Activity, 作用和单独使用FLAG_ACTIVITY_CLEAR_TOP是一样.(此点类同与第二点)
如taskAffinity解释的一样, 在我们没有引入taskAffinity时(android:affinity=xxx.xxx.xxx), 同一个应用中, 使用各种Intent flag都并不会创建新的Task.
taskAffinity需结合FLAG_ACTIVITY_NEW_TASK使用, 此时会再新的Task中寻找/创建待启动的Activity实例.
强烈建议 FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_CLEAR_TOP结合使用,单独使用FLAG_ACTIVITY_NEW_TASK可能会遇到问题(系统会在android:affinity=xxx.xxx.xxx的Task中找有没有已经存在的A的实例, 发现Task中有. 于是乎, 想重用A. 然而并没有能销毁B, 让A弹出来接收新的Intent.所以说, 这种情况下, Intent.FLAG_ACTIVITY_NEW_TASK必须结合Intent.FLAG_ACTIVITY_CLEAR_TOP来一起用)。
Intent Flag并不能代替launchMode, 至少在想重用Activity的情况下, 你需要做的是考虑launchMode而非Intent Flag.
个人理解, Intent Flag更多是倾向于用来做Task中的Activity组织. 而launchMode兼顾Task组织和Activity实例的重用.