关于fragment 中onActivityResult()回调的问题

我的首页架构是以activity中一个viewpager,viewpager以activity填充。

ViewPager非常适合用于实现多页面的滑动切换效果

相同的多页面切换可以是TabHost,但是tabhost标题栏需要重写,稍微麻烦一点
所以采用ViewPager来实现滑动切换,网上很多都是使用ViewPager来加载View,做一些静态的页面展示,像导航,图片展示,使用教程等等

具体请看 http://www.cnblogs.com/skiz/archive/2012/10/26/2741649.html


现在定义一下NavActivity中有四个acitivity,其中一个是userActivity,

userActivity中有一个fragment,fragment需要上传头像,所以肯定要跳到onActivityResult()方法


关于onActivityResult()写到哪会调到的问题,相信大家都知道,这个case中fragment中startActivityForResult调onActivityResult()是不行的,(具体参考:http://www.tuicool.com/articles/2eM32a)

Case :当我们从一个Activity启动了一个Fragment,然后在这个Fragment中又去实例化了一些子Fragment,在子Fragment中去有返回的启动了另外一个Activity,即通过startActivityForResult方式去启动,这时候造成的现象会是,子Fragment接收不到OnActivityResult,如果在子Fragment中是以getActivity.startActivityForResult方式启动,那么只有Activity会接收到OnActivityResult,如果是以getParentFragment.startActivityForResult方式启动,那么只有父Fragment能接收(此时Activity也能接收),但无论如何子Fragment接收不到OnActivityResult。

这是一个非常奇怪的现象,按理说,应该是让子Fragment接收到OnActivityResult才对,究竟是什么造成的呢?这是由于某位写代码的员工抱怨没发奖金,稍稍偷懒了,少写了一部分代码,没有考虑到Fragment再去嵌套Fragment的情况。

我们来看看FragmentActivity中的代码:

<span style="font-size:18px;">protected void onActivityResult(int requestCode, int resultCode, Intent data)
  {
    this.mFragments.noteStateNotSaved();
    int index = requestCode >> 16;
    if (index != 0) {
      index--;
      if ((this.mFragments.mActive == null) || (index < 0) || (index >= this.mFragments.mActive.size())) {
        Log.w("FragmentActivity", "Activity result fragment index out of range: 0x" + Integer.toHexString(requestCode));

        return;
      }
      Fragment frag = (Fragment)this.mFragments.mActive.get(index);
      if (frag == null) {
        Log.w("FragmentActivity", "Activity result no fragment exists for index: 0x" + Integer.toHexString(requestCode));
      }
      else {
        frag.onActivityResult(requestCode & 0xFFFF, resultCode, data);
      }
      return;
    }

    super.onActivityResult(requestCode, resultCode, data);
  }</span>

很显然,设计者把Fragment的下标+1左移16位来标记这个request是不是Fragment的,拿到result再解码出下标,直接取对应的Fragment,这样并没有去考虑对Fragment嵌套Fragment做一个Map映射,所以出现了这种BUG。

但是如果我们需要在OnActivityResult的时候处理一些事情的话,我们可以通过在子Fragment中以getParentFragment.startActivityForResult的方式来启动,然后在父Fragment中去接收数据,我们需要在子Fragment中提供一个方法,如:getResultData(Object obj),通过父Fragment中的子Fragment实例去调用这个方法,把相应的数据传过去,然后去更新子Fragment。



但是我这里是不是可以这样解决呢?

NO,事情远没有你想象的那么简单,不过上边的案例对于部分人还是有用的吧!


鉴于这种办法不行,于是我开始调用getActivity().startActivityForResult,

查看UserActicity中的OnActivityResult是不是会执行呢?

NO,WHY?

我还是不死心,于是那我想是不是在navActivity中的OnActivityResult会执行,如果他都不执行的话,没天理啊。

NO,真实的情况就是没天理,还是没有执行,天啊,他难道被丢弃了?


接下里,已经遍体鳞伤的我,带着一颗破碎的心,查看了startActivityForResult的源码:

<span style="font-size:18px;">public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
        if (mParent == null) {
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            if (requestCode >= 0) {
                // If this start is requesting a result, we can avoid making
                // the activity visible until the result is received.  Setting
                // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
                // activity hidden during this time, to avoid flickering.
                // This can only be done when a result is requested because
                // that guarantees we will get information back when the
                // activity is finished, no matter what happens to it.
                mStartedActivity = true;
            }

            final View decor = mWindow != null ? mWindow.peekDecorView() : null;
            if (decor != null) {
                decor.cancelPendingInputEvents();
            }
            // TODO Consider clearing/flushing other event sources and events for child windows.
        } else {
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                // Note we want to go through this method for compatibility with
                // existing applications that may have overridden it.
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
    }</span>

结果发现他竟然走了这:

注意我们要为现有的应用程序,可以通过这种方法去覆盖它的兼容性

<span style="font-size:18px;"> // Note we want to go through this method for compatibility with
 // existing applications that may have overridden it.
 mParent.startActivityFromChild(this, intent, requestCode);</span>
接着我看了startActivityFromChild,

<span style="font-size:18px;"> public void startActivityFromChild(Activity child, Intent intent, 
            int requestCode, Bundle options) {
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, child,
                intent, requestCode, options);
        if (ar != null) {
            mMainThread.sendActivityResult(
                mToken, child.mEmbeddedID, requestCode,
                ar.getResultCode(), ar.getResultData());
        }
    }</span>

走到这里,ar为null,你的请求真的就被丢弃了,

但是为什么?为什么会走这条路呢?


我们回到启动的时候,getActivity(). startActivityForResult

这里的getActivity()是USerActivity,把他带进来,

<span style="font-size:18px;">if (mParent == null) {。。。。。。</span>
<span style="font-size:18px;"> } else {
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                // Note we want to go through this method for compatibility with
                // existing applications that may have overridden it.
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }</span>
这里的
<span style="font-size:18px;">mParent 不是null啊,他外边还有NavActivity啊。
于是走了下边这条路,然后到了
startActivityFromChild这里,
他去找主线程里的UserActivity,但是没找到,ar=null,(这里我不是很理解,也不知道理解的对不对,如果不对,请大神指正。)
</span>

如果是因为这样,那我直接传NavActivity,应该是没有问题了吧,

于是我((Activity) getActivity().getParent()).startActivityForResult,

他直接走了

<span style="font-size:18px;">mParent==null 这条路,于是onActivityResult终于执行了。后边的问题,
不过是广播或者观察者模式更新view的问题了,大家有什么问题,可以留言,有时间一定和大家相互学习。</span>

有问题,请指正,谢谢!









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值