startActivityForResult、setResult、onActivityResult用法精炼详解

时间:2024-03-28 14:14:21

startActivityForResult、setResult、onActivityResult用法精炼详解

一、前期基础知识储备

(1)ActivityManger管理Activity启动

startActivity(Intent intent),启动一个Activity最简单的方式。我们可能会以为startActivity()是一个类方法,启动activity就是针对activity的子类调用该方法。实际并非如此。Activity调用startActivity()方法时,调用请求实际发给了操作系统。准确的的说,该方法调用请求是发送给操作系统的ActivityManager。ActivityManager负责创建Activity实例并调用其onCreate()方法。Activity启动示意图如下:

startActivityForResult、setResult、onActivityResult用法精炼详解

(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, intrequestCode),该方法接收两个参数,第一个是携带了extra的Intent,第二个参数是请求代码requestCode。请求代码是发送给子actoivity,然后在返货给父activity的用户定义整数值。(当一个activity启动多个不同类型的子activity,且需要判断区分消息回馈方时,会要使用到请求码进行区分)

(3)子activity调用setResult()方法回传数据给父Activity

实现子activity返送返回值给父activity,有以下两种setResult()方法可供调用:

public final void setResult(int resultCode)

public final void setResult(int resultCode, Intent data),通常来说,参数result-code可以是以下两个系统预定义常量中的任何一个:

ACTIVITY.RESULT_OK / ACTIVITY_RESULT_CANCELED

使用setResult()方法代码如下:

Intentdata = 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中,代码如下:

Bundleargs = 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返回结果值。