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

时间:2014-11-18 21:48:41

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

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

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

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

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

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

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

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

帮助表示赞赏。谢谢!

4 个答案:

答案 0 :(得分:14)

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

事实上,Fragment中的startActivityForResult()与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); } 不同(请参阅here):

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)); } 看起来像这样(见here):

onActivityResult()

Google在请求代码上使用了一些奇数字节转换,以确保之后只调用了调用片段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); } }

onActivityResult()

将该方法复制到您喜欢的任何地方,并在Fragment中使用它。它的startActivityFromFragment(Fragment fragment, Intent intent, int requestCode, Bundle options)将被调用。

<强>更新: 支持库v23.2已发布,似乎{{1}}现在正在完成工作:)

答案 1 :(得分:2)

ActivityCompat#startActivityForResult()方法只是活动startActivityForResult(Intent, Bundle)方法的代理。从片段类中调用方法并不意味着最终会调用Fragment的{​​{1}},因为我确信你已经发现了。框架已经知道如何知道调用源自哪个类...在这种情况下,唯一正确的行为是调用onActivityResult()的{​​{1}}方法。

听起来最好的选择是按照您在帖子中的建议处理活动的Activity方法中的所有内容。

答案 2 :(得分:0)

您可以在片段中创建一个侦听器接口或简单的公共函数,并将您从中获取活动的onActivityResult()的参数传递给侦听器或片段的公共方法,并在那里执行您想要的工作

答案 3 :(得分:0)

一种简单的方法:

片段中的

 ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation();

 this.startActivityFromFragment(this, intent, requestCode, options);