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

时间:2018-07-16 08:42:16

标签: android fragment

旋转屏幕后获取当前片段时出现问题。

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

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

我想避免使用android:configChanges,因为它应该是最后的选择,并且我不想将其用于一个小问题,而这可能会导致以后的问题。

这是过程的外观

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

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

然后,同步服务向MainActivity报告,如果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);
    }
}

在同步期间,用户旋转屏幕,并且SyncFragment仍然可见并且处于加载模式。

@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()现在返回空值,因此即使可见数据也无法再传递给该片段,并且现在仍停留在加载中。

编辑-进一步研究

因此,当旋转屏幕时,通常会调用MainActivity onCreate。如您所料,在getCurrentFragment()中调用onCreate将返回SyncFragment,因为该片段仍在提交。

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

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

编辑-更多

如果我将getCurrentFragment()放在按钮上单击并在屏幕旋转后单击它,它将返回SyncFragment。仅在onActivityResult中,该方法返回null。

2 个答案:

答案 0 :(得分:0)

更改屏幕方向后,现有活动将被销毁并在此之后重新创建。如果您想保留一个片段,则可以在Fragment的onCreate中使用以下代码,即使更改方向后您也将获得其实例:

setRetainInstance(true);

答案 1 :(得分:0)

问题是ResultReceiver。

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

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

当屏幕方向改变时,保存ResultReceiver的状态。

@Override
protected void onSaveInstanceState(Bundle outState)
{
    //…

    outState.putParcelable("receiver", _syncReceiver);
    super.onSaveInstanceState(outState);
}

在onCreate上再次加载

if (savedInstanceState != null)
    _syncReceiver = savedInstanceState.getParcelable("receiver");

if (_syncReceiver == null)
    _syncReceiver = new SyncResultReceiver(new Handler());

_syncReceiver.setReceiver(this);