一、前期基础知识储备
(1)ActivityManger管理Activity启动
startActivity(Intent intent),启动一个Activity最简单的方式。Activity调用startActivity()方法时,该方法调用请求是发送给操作系统的ActivityManager。ActivityManager负责创建Activity实例并调用其onCreate()方法。Activity启动示意图如下:
(2)父Activity和子Activity
Activity的启动涉及到两个Activity——父Activity和子Activity,父Activity是启动方,即调用startActivity()方法一方,子Activity是被启动方,即被startActivity()方法打开的一方。
本篇文章的目的,即是分析实现父Activity打开子Activity的方法startActivityForResult()和实现子Activity回传结果给父Activity的方法setResult()、onActivityResult()。
二、从子Activity获取返回结果
(1)使用intent extra附加数据
Intent是四大组件之间和四大组件与操作系统之间通信的一种媒介工具。我们将需要传递的数据作为extra信息,附加给startActivity(Intent)方法的Intent上发送出去。extra是一种key-value结构。
调用Intent.putExtra()方法将extra信息添加给intent,Intent.putExtra()方法有多种形式。不变的是,它总是有两个参数。一个参数是固定为String类型的Key。另一个参数值可以是多种数据类型:包括8种基本数据类型和实现了Serializable接口的类的实例对象。子activity调用对应的getxxextra()方法对extra进行解析即可获取父activity发送过来的数据。
()父activity调用startActivityForResult()方法启动子activity
父activity为了从子activity中获取返回结果,所以调用启动子activity的另外一种方法startActivityForResult(Intent intent, int requestCode),该方法接收两个参数,第一个是携带了extra的Intent,第二个参数是请求代码requestCode。请求代码是发送给子activity,然后再返回给父activity的用户定义整数值。(当一个activity启动多个不同类型的子activity,且需要判断区分消息回馈方时,会要使用到请求码进行区分)
(3)子activity调用setResult()方法回传数据给父Activity
实现子activity返送返回值给父activity,有以下两种setResult()方法可供调用:
public final void setResult(int resultCode)
public final void setResult(int resultCode, Intent data),通常来说,参数resultCode可以是以下两个系统预定义常量中的任何一个:
Activity.RESULT_OK / Activity.RESULT_CANCELED
使用setResult()方法代码如下:
Intent data = new Intent();
data.putExtra(EXTRA_ANSWER_SHOWN,isAnswerShown);
setResult(RESULT_OK, data);
如果子activity是以startActivityForResult()方法启动的,结果代码则总是会返回给父Activity。子activity可以不调用setResult()方法,如果不需要区分附加在intent上的结果或者其他信息,可以让操作系统发送默认的结果代码。
(4)父Activity调用onActivityResult()方法接收子activity返回的数据
在用户单击后退键从子activity回到父activity时,ActivityManager会调用父activity的onActivityResult(int requestCode,int resultCode, Intent data)方法。该方法接收三个参数:第一个为父activity中定义的原始请求代码以及传入的setRresult()方法结果代码和intent。
使用onActivityResult()方法代码如下:
protectedvoid onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode== SEND_SMS_REQUEST) {
if (resultCode == RESULT_OK) {
Toast.makeText(this, "…", Toast.LENGTH_SHORT).show();
}else if (resultCode == RESULT_CANCELED) {
Bundle bundle =data.getExtras();
String phoneno =bundle.getString("phoneNO");
Toast.makeText(this, "…", Toast.LENGTH_SHORT).show();
}
}
三、延伸知识:使用fragment argument
每个fragment实例都可附带一个Bundle对象。该bundle包含有key-value对,我们可以如同附加extra到activity的intent中那样使用它们。一个key-value对即一个argument。
(1)创建Bundle对象
要创建fragment argument,首先需创建Bundle对象。然后,使用Bundle限定类型的“put”方法(类似于intent的方法),将argument添加到bundle中,代码如下:
Bundle args = new Bundle();
args.putSerializable(EXTRA_MY_OBJECT,myObject);
args.putInt(EXTRA_MY_INT,myInt);
args.putCharSequence(EXTRA_MY_STRING,myString);
(2)附加argument给fragment
附加argument bundle给fragment实例时,需调用Fragment-setArguement(Bundle)方法,注意,该任务必须在fragment创建后、添加给activity前完成。
为满足以上苛刻的要求,Android开发者遵循的习惯做法是:添加名为newInstance()的静态方法给Fragment类。在该方法中完成fragment实例以及bundle对象的创建,然后将argument放入到bundle,最后附加给fragment。
托管activity需要fragment实例时,需调用newInstance()方法,而非直接调用其构造方法。而且为满足fragment创建argument的要求,activity可传入任何需的参数给newInstace()方法。
Fragment中创建newInstance()方法的代码如下:
public static CrimeFragment newInstance(UUIDcrimeId) {
Bundle args = new Bundle();
args.putSerializable(EXTRA_CRIME_ID,crimeId);
CrimeFragment fragment = newCrimeFragment();
fragment.setArguments(args);
return fragment;
}
托管Activity中实例化fragment对象的代码如下:
protected Fragment createFragment() {
UUID crimeId = (UUID) getIntent()
.getSerializableExtra(CrimeFragment.EXTRA_CRIME_ID);
return CrimeFragment.newInstance(crimeId);
}
Fragment中获取argument的代码如下:
public void onCreate(@Nullable BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
UUID crimeId =
(UUID) getArguments().getSerializable(EXTRA_CRIME_ID);
mCrime =CrimeLab.get(getActivity()).getCrime(crimeId);
}
(3)Fragment获取Activity回传的数据
Fragment开启Activity时,我们调用的是Fragment.startActivityForResult()方法,而非activity的startActivityForResult()方法;接收数据时是使用Fragment.onActivityResult()方法,而非activity的onActivityResult()方法。
注意,从fragment中返回结果的处理稍有不同。Fragment能够从activity中接收返回结果,但其本身无法产生和返回结果。只有activity拥有返回结果。因此,尽管frgament有startActivityForResult()方法和onActivityResult()方法,但是却不具有任何的setResult()方法。相反,我们应通知托管activity返回结果值。