startActivityForResult(),从名字就能看出来,意思是为了得到结果数据来启动一个Activity。仔细分析一下:为了得到数据,可以有各种途径,比如说通过封装工具类、通过网络等,但这里为什么要通过Activity呢?不难想到,Activity可以和用户交互,得到一些数据,这是其他途径所做不到的。由此,startActivityForResult()的使用场景就清晰了。
一、使用场景
当主Activity需要某一模块的用户数据时,可以通过启动一个“拥有’可以和用户交互得到这一模块数据’功能的Activity”,来获取所需的用户数据。比如:启动一个“用户信息填写表Activity”、“相册选择Activity”。
二、requestCode、resultCode的用法
有时候在一个项目中会有很多个startActivityForResult()交织在一起,如果处理不好,就会显得很乱,而且还容易出错。比如:一个Activity里有好几个入口进入同一个Activity获取不同的数据,一个Acitivity有好几个入口进入不同的Activity等等。
下面是我自己想到的一个方法,可以很好的在一个项目中管理好这些错综复杂的startActivityForResult():
1、标识到哪个Activity去拿哪些数据。
如果是到系统的Activity里去拿数据,那么拿哪些数据就不是你能决定的了,因为系统的Activity里的代码已经写好了。比如选取照片,那么返回的照片只能是我们选择的照片。
如果是到自己定义的Activity里去拿数据,那么我们可以通过intent传一个标识(这个标识可以就用requestCode的常量),告诉目标Activity我们要拿取哪些数据。比如到一个用户信息填写表Activity,我们可以通过标识来确定是返回全部数据,还是部分数据。
这些常量可以在任意Activity里通用。
2、想到哪个Activity拿哪些数据,就从requestCode的常量里选择哪个进行传递。
3&4、如果是自己写的Activity,那么就从intent里拿取标识,依据这个标识分支返回需要返回的数据。
5、如果有相应的数据返回,那么就设置为RESULT_OK,如果无相应的数据返回,就设置为RESULT_CANCEL
三、setResult()的调用时机
1、A启动B,我们可以在B的onStop()里调用setResult()吗?答案是否定的,如下图,在B的onStop()被调用时,A的onActivityResult()已经被调用了,这时显然已经晚了。
B—onPause
A—onActivityResult
A—onRestart
A—onStart
A—onResume
B—onStop
B—onDestroy
2、那我们在B的onPause()里调用setResult()可以吗?答案也是否定的。因为系统是在onFinish()里通过Binder、AMS等一系列操作返回result,而onPause()是在onFinish()之后,所以这个时候再往Activity里塞值已经没有意义了。所以,我们要在系统向A返回result之前就往Activity里塞值,也就是要在onFinish()之前。
3、onCreate()在onFinish()之前,那么我们可以在onCreate()里塞值吗?显然也不可以,都说了,启动B的作用是为了得到用户交互的数据,可是在onCreate()时,界面都还没出来,何谈拿到用户交互的数据呢?
4、那么我们在何时调用setResult()呢?有两种使用场景:
——按back键,系统会自动调用onFinish(),我们在此之前setResult()即可:
@Override
public void onBackPressed() {
setResult();
super.onBackPressed();
}
——点击事件,我们自己调用onFinish(),并在此之前setResult()
setResult();
finish();
执行过程为:
B—setResult
B—finish
B—onPause
A—onActivityResult
A—onRestart
A—onStart
A—onResume
B—onStop
B—onDestroy
四、PS
requestCode必须>=0,否则startActivityForResult()的效果将变成startActivity()。