Android - 当屏幕方向改变时,DialogFragment 中目标 Fragment 发生变化

6
我有一个片段,它向选项菜单添加一个选项。当单击此选项时,会打开一个对话框片段。对话框将原始片段设置为其目标片段。如果在对话框片段打开时没有发生方向更改,则目标片段符合预期。但是,在方向更改后,目标片段被设置为对话框片段本身,而不是之前设置的片段。因此,当尝试将目标片段强制转换为设定的片段时,我会得到一个ClassCastException。我需要在我的对话框中获取目标片段,因为它实现了回调(OnStartOrRestartLoader)。
在实现OnStartOrRestartLoader的片段(VirsārstsFragment)中,我按以下方式创建对话框:
FragmentManager fm = getChildFragmentManager();
SearchDialogFragment dialog = new SearchDialogFragment();
dialog.show(fm, "searchDialog");
dialog.setTargetFragment(this, DIALOGFRAGMENT);

然后在SearchDialogFragment中,我执行以下操作来设置回调:

OnStartOrRestartLoader callback = (OnStartOrRestartLoader) getTargetFragment();

日志记录:

08-25 12:15:55.087: E/AndroidRuntime(10057): FATAL EXCEPTION: main
08-25 12:15:55.087: E/AndroidRuntime(10057): Process: com.example, PID: 10057
08-25 12:15:55.087: E/AndroidRuntime(10057): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example/com.example.MainActivity}: java.lang.ClassCastException: com.example.SearchDialogFragment cannot be cast to com.example.OnStartOrRestartLoader
08-25 12:15:55.087: E/AndroidRuntime(10057):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2224)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2273)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3759)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at android.app.ActivityThread.access$900(ActivityThread.java:141)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1208)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at android.os.Handler.dispatchMessage(Handler.java:102)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at android.os.Looper.loop(Looper.java:136)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at android.app.ActivityThread.main(ActivityThread.java:5052)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at java.lang.reflect.Method.invokeNative(Native Method)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at java.lang.reflect.Method.invoke(Method.java:515)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at dalvik.system.NativeStart.main(Native Method)
08-25 12:15:55.087: E/AndroidRuntime(10057): Caused by: java.lang.ClassCastException: com.example.SearchDialogFragment cannot be cast to com.example.OnStartOrRestartLoader
08-25 12:15:55.087: E/AndroidRuntime(10057):    at com.example.SearchDialogFragment.onCreateDialog(SearchDialogFragment.java:59)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at android.support.v4.app.DialogFragment.getLayoutInflater(DialogFragment.java:307)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:942)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1121)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1103)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1901)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at android.support.v4.app.Fragment.performActivityCreated(Fragment.java:1518)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:962)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1121)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1103)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1901)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:567)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1171)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at android.app.Activity.performStart(Activity.java:5322)
08-25 12:15:55.087: E/AndroidRuntime(10057):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2187)
08-25 12:15:55.087: E/AndroidRuntime(10057):    ... 13 more

你能发更多的代码吗? - Blackbelt
你的用户界面会随着方向变化而改变吗?我的意思是,你是否有不同的用户界面来显示每个方向? - pvn
我不明白。getTargetFragment()返回一个Fragment,而你正在尝试将其转换为OnStartOrRestartLoader。异常非常清楚。你想做什么? - Simon
@Simon,现在我想起来你说的是对的,但是即使我尝试将其转换为扩展Fragment的VirsārstsFragment,问题仍然存在。我通过使用getParentFragment而不是getTargetFragment找到了解决方案。 - Dāvis Sparinskis
@pvn 相同的用户界面。我通过程序添加旋转器和文本视图,并希望在旋转后保留它们的内容(这是有效的)。当我点击正按钮时,我需要在父碎片中使用新参数重新启动 cursorLoader(仅在没有方向更改时有效)。 - Dāvis Sparinskis
4个回答

5

setTargetFragment 不应该被用于建立父子片段之间的关系。它只应该用于链接兄弟片段(即与同一 FragmentManager 中存在的片段)。

不能在父子片段之间使用它的原因是片段的目标会保存并恢复为其自己的 FragmentManager 中的索引。因此,在框架恢复例如方向更改后的活动时,一切都将顺利进行。此时,FragmentManager 将在自身中寻找目标片段,而不是父级 FragmentManager


3
我仍然不明白为什么getTargetFragment()没有起作用,但是将其替换为getParentFragment()解决了我的问题。

我还必须使用 getChildFragmentManager() 而不是 getFragmentManager()。https://dev59.com/rmUq5IYBdhLWcg3wF8dQ#19077209 - Eric

0

虽然已经很晚了,但我今天遇到了这个问题,并想把我的解决方案写下来,以便有需要的人参考。

这里的问题是您将 VirsārstsFragment 的 ChildFragmentManager 传递给了 SearchDialogFragment。

FragmentManager fm = getChildFragmentManager();
SearchDialogFragment dialog = new SearchDialogFragment();
dialog.show(fm, "searchDialog");

相反,您需要传递普通的片段管理器(通过使用getFragmentManager()获取)。

我认为您的代码在恢复时不起作用,因为系统在寻找您传递给SearchDialogFragment的childFrgamentManager中的VirsārstsFragment,但是找不到它,因为VirsārstsFragment实际上在活动的片段管理器中。将Activity的片段管理器传递给SearchDialogFragment可以解决此问题。


-4
如果没有UI更改,您可以在清单中的活动中添加configChanges属性。
<activity
        android:name=".YourActivity"
        android:configChanges="screenSize|orientation"/>

这个功能指定了当屏幕大小或方向发生变化时,配置更改将在活动本身中处理(在您的情况下没有更改,因此无需执行任何操作)

如果您需要处理未来的任何更改,可以在您的活动中的onConfigurationChanged()方法中进行处理。

如果这对您有用,请告诉我。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接