startActivityForResult不回调的问题

大家都知道,可以通过使用 startActivityForResult() 和 onActivityResult() 方法来传递或接收参数。

但你是否遭遇过onActivityResult()不执行或者未按预想的那样执行的情况呢?


一、requestCode 小于0

两个activity传递数据和返回数据时,请求方的onActivityResult始终无响应,通过debug调试模式也没见调用该方法。查看了各种配置和程序代码,均未发现有错误之处。阅读API才发现requestCode >= 0才起作用。有时使用Activity.RESULT_OK,一样不回调,也是因为.RESULT_OK = -1。

源码的startActivityForResult(Intent intent,int requestCode)的requestCode说明是 : If >= 0, this code will be returned in onActivityResult() when the activity exits.


源码是这样的:

   /**
     * Same as calling {@link #startActivityForResult(Intent, int, Bundle)}
     * with no options.
     *
     * @param intent The intent to start.
     * @param requestCode If >= 0, this code will be returned in
     *                    onActivityResult() when the activity exits.
     *
     * @throws android.content.ActivityNotFoundException
     *
     * @see #startActivity 
     */
    public void startActivityForResult(Intent intent, int requestCode) {
        startActivityForResult(intent, requestCode, null);
    }
重要的是这一句:如果用负值的 requestCode和调用startActivity是一样的,所以代码不走startActivityForResult而是startActivity


Using a negative requestCode is the same as calling
     * {@link #startActivity} (the activity is not launched as a sub-activity).


 /**
     * Launch an activity for which you would like a result when it finished.
     * When this activity exits, your
     * onActivityResult() method will be called with the given requestCode. 
     * Using a negative requestCode is the same as calling 
     * {@link #startActivity} (the activity is not launched as a sub-activity).
     *
     * <p>Note that this method should only be used with Intent protocols
     * that are defined to return a result.  In other protocols (such as
     * {@link Intent#ACTION_MAIN} or {@link Intent#ACTION_VIEW}), you may
     * not get the result when you expect.  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.
     *
     * <p>As a special case, if you call startActivityForResult() with a requestCode 
     * >= 0 during the initial onCreate(Bundle savedInstanceState)/onResume() of your
     * activity, then your window will not be displayed until a result is 
     * returned back from the started activity.  This is to avoid visible 
     * flickering when redirecting to another activity. 
     *
     * <p>This method throws {@link android.content.ActivityNotFoundException}
     * if there was no Activity found to run the given Intent.
     *
     * @param intent The intent to start.
     * @param requestCode If >= 0, this code will be returned in
     *                    onActivityResult() when the activity exits.
     * @param options Additional options for how the Activity should be started.
     * See {@link android.content.Context#startActivity(Intent, Bundle)
     * Context.startActivity(Intent, Bundle)} for more details.
     *
     * @throws android.content.ActivityNotFoundException
     *
     * @see #startActivity 
     */
    public void startActivityForResult(Intent intent, int requestCode, Bundle options) {}


 /**
     * Same as {@link #startActivity(Intent, Bundle)} with no options
     * specified.
     *
     * @param intent The intent to start.
     *
     * @throws android.content.ActivityNotFoundException
     *
     * @see {@link #startActivity(Intent, Bundle)}
     * @see #startActivityForResult
     */
    @Override
    public void startActivity(Intent intent) {
        startActivity(intent, null);
    }

进入这个方法startActivity(Intent intent, Bundle bundle):

 /**
     * Launch a new activity.  You will not receive any information about when
     * the activity exits.  This implementation overrides the base version,
     * providing information about
     * the activity performing the launch.  Because of this additional
     * information, the {@link Intent#FLAG_ACTIVITY_NEW_TASK} launch flag is not
     * required; if not specified, the new activity will be added to the
     * task of the caller.
     * 
     * <p>This method throws {@link android.content.ActivityNotFoundException}
     * if there was no Activity found to run the given Intent.
     * 
     * @param intent The intent to start. 
     * @param options Additional options for how the Activity should be started.
     * See {@link android.content.Context#startActivity(Intent, Bundle)
     * Context.startActivity(Intent, Bundle)} for more details.
     * 
     * @throws android.content.ActivityNotFoundException
     *
     * @see {@link #startActivity(Intent)}
     * @see #startActivityForResult 
     */
    @Override
    public void startActivity(Intent intent, Bundle options) {
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }

于是我就看出为什么了,RESULT_OK在Activity中的值就是-1,所以如果我们给的请求码是-1的时候是就相当于使用startActivity(),这样是不会调用onActivityForResult方法的。

二、 launchMode为singleTask或者singleInstance

 通过startActivityForResult()方式去启动launchMode=singleTask或者的Activity,onActivityResult()会被立即回调且resultCode值为RESULT_CANCEL。

API里面也有说明:startActivityForResult(Intent intent, int requestCode, Bundle options)的注释里有一段话是这样说的:

Note that this method should only be used with Intent protocols
     * that are defined to return a result.  In other protocols (such as
     * {@link Intent#ACTION_MAIN} or {@link Intent#ACTION_VIEW}), you may
     * not get the result when you expect.  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.

发生这种情况的深层原因呢,在http://developer.android.com/guide/components/tasks-and-back-stack.html文档里也有说明:


在下图中,存在着前两个栈,其中直接显示在屏幕上与用户交互的Back Stack,及另一个隐藏在后台的Background Task,该栈栈顶的Activity Y其launchModesingleTask

如果在Activity 2中调用BackgroundTask中已经启动过的Activity Y,则Background Task内占据屏幕并且该Task下所有的栈都会保留当前的栈位置及顺序push进Back Task形成新的结构,顺序由上至下为Activity Y→Activity X→Activity 2→Activity 1。

在Activity Y界面按返回键,则ActivityY出栈,Activity X占据屏幕!注意,由Activity2调用的Activity Y,但返回键后,回退显示的是Activity X所以即使在Activity Y执行setResult(),Activity 2也是无法接收到的。更通俗的讲就是:standard 模式的Activity 2  startActivityForResult(new Intent(Activity 2,Activity Y.class), requestCode)其中Activity Y是singleTask,然后Activity Y再设置setResult(resultCode);,这样的话,Activity 2的onActivityResult(int requestCode, int resultCode, Intent data)很可能接收不到数据。

继续按返回键,则才回到Activity 2。

在这种Tasks的入栈与出栈设计下,由于可能有Activity X的存在,所以在Activity 2启动Activity Y时,则直接回调了onActivityResult()并给出了RESULT_CANCEL也就可以理解了。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值