使用startActivityForResult一定要注意Activity的启动模式。如果不注意执行startActivityForResult,没等到被调用的 Activity 返回,onActivityResult() 就被执行了。将lanchMode设置为标准模式就好了。
看api的注释:For example, if the activity you
* are launching uses the singleTask launch mode, it will not run in your
* task and thus you will immediately receive a cancel result.
分享一个我在实际开发中遇到的例子。
问题描述如下:
要求最一个商家注册功能的实现,里面有个服务选项,这个服务选项是有两级分类组成,没个用户只能选择一级分类的下面的二级分类,不可以跨组选分类。选择后肯定要将数据显示到注册页面上。
我的实现方法是这样的:设注册页面的Activity为A,一级分类的Activity为B,二级分类的Activity为C。
主要看A中Intent启动的是B,如何收到C的数据的!其他数据可以忽略,可以根据项目中的需要,传递。
A:
public class A_Activity extends Activity { private TextView mTv_a; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.a_activity); mTv_a = (TextView) findViewById(R.id.tv_a); mTv_a.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub Intent intent = new Intent(A_Activity.this, B_Activity.class); // 指定启动B intent.putExtra("DATA1", "从A中传入的数据"); startActivityForResult(intent, 1); } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { // TODO Auto-generated method stub if(requestCode == 1 && resultCode == 1){ Log.d("TAG",intent.getStringExtra("DATA3")); } super.onActivityResult(requestCode, resultCode, intent); } }
B:
public class B_Activity extends Activity { private TextView mTv_b; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.b_activity); mTv_b = (TextView) findViewById(R.id.tv_b); mTv_b.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub Intent intent = new Intent(B_Activity.this, C_Activity.class); intent.putExtra("DATA2", "从B中传入的数据"); startActivityForResult(intent, 2); } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { // TODO Auto-generated method stub if(requestCode == 2 && resultCode == 2){ B_Activity.this.setResult(1, intent); B_Activity.this.finish(); } super.onActivityResult(requestCode, resultCode, intent); } }
C:
public class C_Activity extends Activity { private TextView mTv_c; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.c_activity); mTv_c = (TextView) findViewById(R.id.tv_c); mTv_c.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub Intent intent = getIntent(); intent.putExtra("DATA3", "从C中传入的数据"); C_Activity.this.setResult(2, intent); C_Activity.this.finish(); } }); } }
在B中 B_Activity.this.setResult(1, intent);
B_Activity.this.finish();
是关键。Android中肯定有相关方法处理这样的功能,我这种方法可能算是麻烦的了,大家如果有其他方法,欢迎留言,提出。
第二种方法是通过onNewIntent实现,这个就更加简单了。
当从栈中启动一个已经存在的Activity时,系统不会再执行onCreate方法,而是执行onNewIntent方法
(1)Activity第一启动的时候执行onCreate()---->onStart()---->onResume()等后续生命周期函数,也就时说第一次启动Activity并不会执行到onNewIntent().
(2) 而后面如果再有想启动Activity的时候,那就是执行onNewIntent()---->onResart()------>onStart()----->onResume().
(3)如果android系统由于内存不足把已存在Activity释放掉了,那么再次调用的时候会重新启动Activity即执行onCreate()---->onStart()---->onResume()等。
所以如果使用onNewIntent,执行返回的操作,1、要将此Activity的lanchMode设置为singleTask。2、另外一个Activity要通过intent请求此Activity。也可以通过Intent.FLAG_ACTIVITY_SINGLE_TOP标志启动Activity,效果跟android:launchmode="singleTask"一样。
另外,不要忘记,系统可能会随时杀掉后台运行的Activity,如果这一切发生,那么系统就会调用onCreate方法,而不调用onNewIntent方法,一个好的解决方法就是在onCreate和onNewIntent方法中调用同一个处理数据的方法。
如何区别从Activity B跳转到onNewIntent操作的Activity A呢?
是在Activity B中的intent中设置标志值,然后通过if判断:
if (intent.getBooleanExtra("LOGIN", false)) {}