【问题标题】:Lifecycle of hidden fragment隐藏片段的生命周期
【发布时间】:2015-11-08 09:01:53
【问题描述】:

我想了解Android中Activity生命周期和Fragment生命周期的交互,所以决定新建一个项目,从this page复制代码。
然后我认为,为了提高我的理解力,在平板电脑上测试它,切换它的方向并看看它会发生什么(尽管它可能不是为此而设计的)会很有用。 通过 logcat,我跟踪了在活动和国家片段上触发的主要事件,例如在 Activity Oncreate 我写的:

Log.d("TAG", "Activity: 1.onCreate");

这是我从纵向视图开始然后旋转时得到的:

标签:活动:1.onCreate
标签: 活动: 2.onStart
标签:## ContryFrag:1.onAttach
标签:## ContryFrag:2.onCreateView
标签:## ContryFrag:3.onStart
标签: 活动: 3.onResume
标签:## ContryFrag:4.onResume
标签:活动:-3.onPause
标签:## ContryFrag:-4.onPause
标签:活动:-2.onStop
标签:## ContryFrag:-3.onStop
标签:活动:-1.onDestroy
标签:## ContryFrag:-2.onDestroyView
标签:## ContryFrag:-1.onDetach
标签:活动:1.onCreate
标签:## ContryFrag:1.onAttach
标签:## ContryFrag:1.onAttach
标签:## ContryFrag:2.onCreateView
标签: 活动: 2.onStart
标签:## ContryFrag:2.onCreateView
标签:## ContryFrag:3.onStart
标签:## ContryFrag:3.onStart
标签: 活动: 3.onResume
标签:## ContryFrag:4.onResume
标签:## ContryFrag:4.onResume

似乎在纵向视图中通过 FragmentManager 添加的片段在旋转后仍会重新创建,尽管它之前已分离。重新开始的事件链会被再次跟踪,即使它不会显示。
你能帮我理解这里发生了什么吗?

编辑

当我检查片段是否 isInLayout()

Log.d("TAG", "## ContryFrag: 1.onAttach /" + isInLayout() );

我意识到旋转后有两个片段:一个是通过旋转创建的,另一个似乎是先前活动的剩余部分(不应该是)。

标签:活动:1.onCreate
标签:## ContryFrag:1.onAttach /false
标签:## ContryFrag:1.onAttach /true
标签:## ContryFrag:2.onCreateView /true
标签: 活动: 2.onStart
标签:## ContryFrag:2.onCreateView /false
标签:## ContryFrag:3.onStart /false
标签:## ContryFrag:3.onStart /true
标签: 活动: 3.onResume
标签:## ContryFrag:4.onResume /false
标签:## ContryFrag:4.onResume /true

编辑 2

这是我用来获取onSelectedCountry(String country)的虚拟代码,没有提供:

public void onSelectedCountry(String country)
{
    String[] x = {country, "city0", "city1", "city2", "city3", "city4", "city5"};
    adapter.clear();
    adapter.addAll(x);
}

编辑 3

这里是my code。抱歉耽搁了,我是第一次使用github。

【问题讨论】:

  • 可能是因为你的日志。在您的City fragment 中查看。在landscape 模式下,我认为city 片段和country 片段记录相同的内容。
  • 你的意思是说发送消息给logcat的代码可能也被City Fragment调用了?不,我只在主要活动和国家/地区片段中添加了代码。
  • 为方便起见,最好在帖子中发布一些代码。发布的链接未显示所有代码。例如,是否有 Activity.onStart() 的代码?
  • 唯一缺少的代码是提供国家和城市列表的代码。所以我实现了我的虚拟 getCountries() 和 getCitiesByCountry(country) 函数。除此之外,所有代码都显示在该页面中,并且该应用程序运行良好。只有彻底调试它,你才会发现我注意到了什么。
  • 您尚未发布任何代码来显示您如何创建片段。仅仅显示日志语句的输出是不够的。你的问题到底是什么?是“为什么要添加多个片段”吗?如果是这样,请显示您创建片段的代码。

标签: android android-fragments android-lifecycle


【解决方案1】:

Fragment 添加到FragmentManager 后,它会一直保留在那里,直到您手动删除它或直到Activity 永久完成。 (重启Activity,例如设备旋转时发生的事情不会导致它完成)

旋转设备不会清除碎片。如果您在Activity 生命周期中的任何时间创建一个新的Fragment 并将其添加到FragmentManager,而不首先检查Fragment 是否已存在于FragmentManager 中,您只需添加一个新的Fragment每次您执行任何导致 Activity 重新启动的操作时。

例如,此代码应该只允许添加您的片段的一份副本。

protected void onResume() {

    String TAG = "COUNTRYFRAG";

    CountryFrag f = (CountryFrag) getSupportFragmentManager().findFragmentByTag(TAG);

    if (f == null) {
        f = new CountryFrag();
        getSupportFragmentManager().beginTransaction()
                .add(f, TAG)
                .commit();
    }

    int count = getSupportFragmentManager().getFragments().size();
    Log.v("FRAGS", "There are " + count + "fragments in the fragment manager.");

}

而这个会在您每次旋转设备时添加一个新的。

protected void onResume() {

    String TAG = "COUNTRYFRAG";

        CountryFrag f = new CountryFrag();
        getSupportFragmentManager().beginTransaction()
                .add(f, TAG)
                .commit();

    int count = getSupportFragmentManager().getFragments().size();
    Log.v("FRAGS", "There are " + count + "fragments in the fragment manager.");

}

链接处的代码似乎是使用savedInstanceState的存在来判断是添加Fragment还是从方法返回。这是不可靠的,因为您可能没有在状态中保存任何内容,因此它可能始终为空。最好专门检查一下是否已经添加了 Fragment。

if (savedInstanceState != null) 
            return;

【讨论】:

  • 感谢您的帮助。看来,当活动以纵向模式启动时,它通过片段管理器添加了 CountryFragment。然后在横向旋转之后,添加了一个新的 CountryFragment,因为它是布局 xml 文件所需要的。也许检查 savedInstanceState 不是避免重复插入片段的最佳方法,但在这种情况下它不是罪魁祸首。尽管片段管理器没有添加新片段,但我们现在有两个 CountryFragment。奇怪的是,它们都被附加、创建查看、启动和恢复,即使只显示了一个。
  • 旋转回纵向模式后,我们仍然有两个 CountryFragment:第一个和第一次旋转后添加的一个。 savedInstanceState 的条件有效。然后如果在横向模式下第二次旋转,现在不会添加新的 CountryFragments。似乎有一种内置机制可以防止从布局输出资源中重复插入片段,
  • 我并没有试图修复你引用的具体案例,因为你说你不想要那个。我的回答是解释为什么您会看到您所看到的行为,这是因为由于检查之前是否添加了片段而添加了多个片段。
  • 回复您上面的评论,这两个片段都已添加到您的容器中。您只看到一个,因为它们是相同的并且直接放在彼此之上。
  • 正如我之前所说,我不理解您链接的页面,但 XML 添加了一个片段。如果您还在代码中添加片段,那么您最终将得到 2 个片段。您通常会使用一种方法或另一种方法,但不能同时使用两种方法。 XML 更具限制性,因为您仅限于其中定义的片段。
【解决方案2】:

您似乎没有使用片段的前一个实例。 当 Activity 由于配置更改而重新启动时,Android 会保留 Fragment 布局和关联的返回堆栈。 看起来当 Activity 重新创建时,会创建一个新片段。 尝试将以下代码添加到您的 Activity 的 onCreate 中:

@Override
public void onCreate(Bundle savedInstanceState) {

        ...    

    ContryFrag fragment = (ContryFrag) mFragmentManager.findFragmentById(R.id.fragment_container); 

    if (fragment == null) {
        FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
        fragmentTransaction.add(R.id.fragment_container, new ContryFrag());
        fragmentTransaction.commit();
    }
}

并删除片段创建的代码。

【讨论】:

  • 奇怪的行为并没有消失。无论如何,我的目标不是解决问题,而是了解我报告的原因。该代码可在我发布的链接中找到,它是可重现的。
【解决方案3】:

链接的文章在布局 xml 中定义了片段。您在 github 中的代码正在按代码创建和添加片段。你这两个一起用吗?

【讨论】:

  • 代码相同。它通过代码或 xml 创建和添加片段,具体取决于其方向(横向或纵向)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-28
  • 1970-01-01
  • 1970-01-01
  • 2013-08-24
  • 2021-01-11
  • 1970-01-01
相关资源
最近更新 更多