FragmentManger findFragmentById 在屏幕方向更改后返回 null



屏幕旋转后获取当前片段时遇到问题。

我有一个同步服务,它向MainActivity报告进度,如果该片段当前已提交,则反过来将数据传递给SyncFragment

但是,如果在同步过程中旋转了屏幕,则getSupportFragmentManager().findFragmentById(R.id.crossfade_content)返回 null,即使 SyncFragment 仍已提交且可见,并且 MainActivity 无法向 SyncFragment 报告任何进度,并且即使同步已完成,屏幕也只是卡在加载时。

我想避免使用android:configChanges因为它应该是最后的手段,我不想将它用于一个可能导致我进一步出现问题的小问题。

这就是过程的样子

首先提交同步片段,然后从那里启动同步服务。

getSupportFragmentManager().beginTransaction()
.replace(R.id.crossfade_content, SyncFragment.newInstance(true))
.commit();

然后,同步服务向 MainActivity 报告,如果它当前处于活动状态,则会将报告转换为 SyncFragment。

@Override
public void onReceiveResult(int resultCode, Bundle resultData)
{
//…
//Report progress to SyncFragment if it is active
Fragment fragment = getCurrentFragment();
if (getCurrentFragment() instanceof SyncFragment)
{
SyncFragment syncFragment = (SyncFragment)fragment;
syncFragment.reportSyncProgress(resultCode, resultData);
}
}

在同步过程中,用户会旋转屏幕,同步片段仍然可见并处于加载模式。

@Override
public void onReceiveResult(int resultCode, Bundle resultData)
{
//…
//Report progress to SyncFragment if it is active
Fragment fragment = getCurrentFragment(); // <-- This is now returning null
if (getCurrentFragment() instanceof SyncFragment)
{
SyncFragment syncFragment = (SyncFragment)fragment;
syncFragment.reportSyncProgress(resultCode, resultData);
}
}

由于getCurrentFragment()现在返回 null,因此即使数据可见,也无法再将数据传递到片段,并且现在卡在加载时。

编辑 - 进一步研究

因此,当屏幕旋转时,MainActivity onCreate被正常调用。在onCreate中调用getCurrentFragment()将如您所期望的那样返回 SyncFragment,因为该片段仍在提交。

但是,在onReceiveResult中(在 onCreate 之后调用),相同的函数 (getCurrentFragment()) 返回 null。

此外,当屏幕旋转时,onAttachFragment确实会被调用,并且 SyncFragment 会像预期的那样传递给该函数。但是,由于某种原因,如果我在屏幕旋转后使用该片段的引用,则会出现片段未附加到上下文的错误。

编辑 - 更多

如果我将getCurrentFragment()放在按钮单击上并在屏幕旋转后单击它,它会返回同步片段。只有在 onActivityResult 中,该方法才返回 null。

当屏幕方向发生变化时,现有活动将被销毁,并在之后重新创建。如果你想保留一个片段,你可以在你的片段的onCreate中使用以下代码,那么即使在方向发生变化之后,你也会得到它的实例:

setRetainInstance(true);

问题是 ResultReceiver。

重新创建活动后,ResultReceiver 无法正确报告,因此解决方案是保存其状态。

回顾我的问题,这不是一个明显的解决方案,但如果某个孤独的流浪者遇到与我相同的问题,那么这就是解决方案。

保存屏幕方向更改时的结果接收器的状态。

@Override
protected void onSaveInstanceState(Bundle outState)
{
//…
outState.putParcelable("receiver", _syncReceiver);
super.onSaveInstanceState(outState);
}

在创建时再次加载它

if (savedInstanceState != null)
_syncReceiver = savedInstanceState.getParcelable("receiver");
if (_syncReceiver == null)
_syncReceiver = new SyncResultReceiver(new Handler());
_syncReceiver.setReceiver(this);

最新更新