使用Transition从Fragment启动活动(API 21支持)

Dam*_*rek 17 android android-support-library onactivityresult android-transitions android-5.0-lollipop

我正在尝试将Android应用程序移植到新的支持库(support-v4:21.0.0),并且我无法通过转换从Fragments启动活动.

在我的活动中,我一直在做类似的事情:

Bundle options = ActivityOptionsCompat.makeSceneTransitionAnimation(this).toBundle();
ActivityCompat.startActivityForResult(this, intent, REQUEST_SOMETHING, options);
Run Code Online (Sandbox Code Playgroud)

适用于活动.但是,如果我尝试使用Fragments做类似的事情,例如:

Activity activity = getActivity();
Bundle options = ActivityOptionsCompat.makeSceneTransitionAnimation(activity).toBundle();
ActivityCompat.startActivityForResult(activity, intent, REQUEST_SOMETHING, options);
Run Code Online (Sandbox Code Playgroud)

事实证明,onActivityResult()没有为片段调用,只有封闭的Activity.我没有在支持库中找到任何东西来将选项Bundle作为参数传递startActivityForResult()给实际的Fragment并让它回调到onActivityResult()那个Fragment中.这可能吗?

最简单的解决方案是处理onActivityResult()Activity本身的所有调用,但我宁愿不这样做,因为我有大量可能正在接收回调的片段.

感谢帮助.谢谢!

010*_*101 14

可悲的是,ActivityCompat.startActivityForResult()不能正常工作Fragments(参见Alex Lockwood的回答).几个星期以来,我惊叹于谷歌从来没有给我们一个ActivityCompat等同于Fragment实现的方法startActivityForResult().他们在想什么?!但后来我有了一个想法:让我们来看看该方法是如何实际实现的.

事实上,startActivityForResult()Fragment与Activity中的不同(见这里):

public void startActivityForResult(Intent intent, int requestCode) {
    if (mActivity == null) {
        throw new IllegalStateException("Fragment " + this + " not attached to Activity");
    }
    mActivity.startActivityFromFragment(this, intent, requestCode);
}
Run Code Online (Sandbox Code Playgroud)

现在startActivityFromFragment()看起来像这样(见这里):

public void startActivityFromFragment(Fragment fragment, Intent intent, 
        int requestCode) {
    if (requestCode == -1) {
        super.startActivityForResult(intent, -1);
        return;
    }
    if ((requestCode&0xffff0000) != 0) {
        throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");
    }
    super.startActivityForResult(intent,
                                 ((fragment.mIndex + 1) << 16) + (requestCode & 0xffff));
}
Run Code Online (Sandbox Code Playgroud)

谷歌在请求代码上使用一些奇数字节移位来确保之后只调用调用片段onActivityResult().既然ActivityCompat没有提供任何startActivityFromFragment(),唯一的选择是自己实现它.需要反射才能访问包私有字段mIndex.

public static void startActivityForResult(Fragment fragment, Intent intent,
                                          int requestCode, Bundle options) {
    if (Build.VERSION.SDK_INT >= 16) {
        if ((requestCode & 0xffff0000) != 0) {
            throw new IllegalArgumentException("Can only use lower 16 bits" +
                                               " for requestCode");
        }
        if (requestCode != -1) {
            try {
                Field mIndex = Fragment.class.getDeclaredField("mIndex");
                mIndex.setAccessible(true);
                requestCode = ((mIndex.getInt(this) + 1) << 16) + (requestCode & 0xffff);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
        ActivityCompat.startActivityForResult(fragment.getActivity(), intent,
                                              requestCode, options);
    } else {
        fragment.getActivity().startActivityFromFragment(this, intent, requestCode);
    }
}
Run Code Online (Sandbox Code Playgroud)

将该方法复制到您喜欢的任何地方,并从Fragment中使用它.它onActivityResult()会叫,因为它应该.

更新:支持库v23.2发布了,它似乎startActivityFromFragment(Fragment fragment, Intent intent, int requestCode, Bundle options)现在正在工作:)

  • 我想从Activity调用然后将结果从活动传递给Fragment会更加干净,但是我的活动附加了大量的片段(因为viewpager),这使得它很难处理 (2认同)