android - 使用 Transition 从 Fragment 启动 Activity(API 21 支持)

标签 android android-support-library android-5.0-lollipop onactivityresult android-transitions

我正在尝试将 Android 应用程序移植到新的支持库 (support-v4:21.0.0),但我无法从带有过渡的 fragment 启动 Activity 。

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

Bundle options = ActivityOptionsCompat.makeSceneTransitionAnimation(this).toBundle();
ActivityCompat.startActivityForResult(this, intent, REQUEST_SOMETHING, options);

这适用于 Activity 。但是,如果我尝试对 Fragments 做类似的事情,例如:

Activity activity = getActivity();
Bundle options = ActivityOptionsCompat.makeSceneTransitionAnimation(activity).toBundle();
ActivityCompat.startActivityForResult(activity, intent, REQUEST_SOMETHING, options);

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

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

感谢您的帮助。谢谢!

最佳答案

遗憾的是,ActivityCompat.startActivityForResult()Fragments 中不能正常工作(请参阅 Alex Lockwood 的回答)。几个星期以来,我惊叹于 Google 从未给我们提供与 Fragment 的 startActivityForResult() 实现等效的 ActivityCompat 方法。他们在想什么?!但是后来我有了一个想法:我们来看看这个方法是怎么实现的。

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

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

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

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));
}

Google 在请求代码上使用了一些奇怪的字节移位,以确保之后只调用调用 Fragment 的 onActivityResult()。现在由于 ActivityCompat 没有提供任何 startActivityFromFragment(),剩下的唯一选择就是自己实现它。访问包私有(private)字段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);
    }
}

将该方法复制到您喜欢的任何地方并从您的 Fragment 中使用它。它的 onActivityResult() 将被调用。

更新: 支持库 v23.2 已发布,似乎 startActivityFromFragment(Fragment fragment, Intent intent, int requestCode, Bundle options) 现在可以完成这项工作:)

关于android - 使用 Transition 从 Fragment 启动 Activity(API 21 支持),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27004721/

相关文章:

android - 在圆形表面上显示相机预览(舷窗效果)

android - 无法解决:com.android.support:cardview-v7:26.0.0 android

Android DialogFragment 不会关闭

android - 在 android 应用中 Toolbar.setTitle 方法无效 - 应用名称显示为标题

android - JSON 不适用于 Android Lollipop

java - 将数据从 Activity 发送到 Android 中的 viewpager fragment

android - 字符串引用不应该用于 AndroidManifest 中 Intent 过滤器的操作名称吗?

android - 在可绘制资源 xml 中为 VectorDrawable 着色

适用于 Lollipop 及以上版本的 Android 照片选择器

android - Android L 上的 Couchbase Lite