您的位置:首页 > 其它

startActivityForResult不回调的问题

2016-03-31 14:00 381 查看
大家都知道,可以通过使用 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其launchMode为singleTask

如果在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也就可以理解了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: