【问题标题】:Reusing Fragment View in this way will cause some problems?以这种方式重用 Fragment View 会导致一些问题吗?
【发布时间】:2014-05-07 14:00:53
【问题描述】:

情况就是这样。我在片段 A 中有一个列表视图,其中有一个无限列表,当用户到达底部时,该列表会通过 Web 服务填充。

列表视图中的每个项目都有一个“查看更多”链接,可打开该项目的详细片段 B。

我正在使用 FragmentManager.replace() 方法和“addToBackStack”。 (我是“替换”而不是“添加”,因为我在片段 A 中有我不想在片段 B 中显示的菜单项。我已经尝试了不同的方法来添加片段,而不是在打开时删除并尝试隐藏菜单项片段 B 已经工作,但以一些其他问题结束,所以我更喜欢使用 replace")

假设用户正在查看列表中的第 25 项,然后打开详细信息片段。当用户然后点击后退按钮时,我希望用户继续在同一位置查看列表。

这很容易通过“添加片段”而不是“替换”来实现,因为片段从未被删除。当使用“替换”时,片段被移除,然后当被击退时它会再次渲染(又名,将再次调用 onCreateView)

但是此时,已经为片段创建了视图,因为 FragmentManager.remove 仅从视图层次结构中删除视图,但不会破坏片段。所以我“理论上”可以做这样的事情:

if(view == null){
    //Create view
    view = (ViewGroup) inflater.inflate(R.layout.news_list, container, false);
}
return view;

但在这种情况下,它会导致

java.lang.IllegalStateException: 指定的孩子已经有一个 父母。您必须先在孩子的父母上调用 removeView()。

所以,我的解决方案如下:

if(view == null){
    view = (ViewGroup) inflater.inflate(R.layout.news_list, container, false);
} else {
    ((ViewGroup) view.getParent()).removeView(view);
}
return view;

这对我有用,但我不知道除了这个解决方案之外是否会有一些我现在没有看到的“隐藏”错误。

我想听听您的建议。提前致谢

【问题讨论】:

  • @SteveBennett 我看到了这个问题,我也给出了对我有用的问题的答案。但我现在要问的是,在这个新问题中,解决方案是否可行。我在自己的项目中有这个解决方案,正在工作,但我需要有人告诉我这个解决方案是否会导致我没有看到的其他冲突

标签: android fragment fragmentmanager


【解决方案1】:

为什么不记住直到用户在片段的 onPause 中滚动的位置并将列表视图位置设置为 onResume 中的滚动位置?只是一个想法,我不确定您的解决方案是否有任何不利影响/错误。

  @Override
  public void onPause() {
    // TODO Auto-generated method stub
    super.onPause();

   try{
         index = this.getListView().getFirstVisiblePosition();
         View v = this.getListView().getChildAt(0);
         top = (v == null) ? 0 : v.getTop();
      }
      catch(Throwable t){
         t.printStackTrace();
      }

并且在片段的 onResume 中:

   @Override
public void onResume() {
    // TODO Auto-generated method stub
    super.onResume();

    /**
     *  Check to see if there is any scroll position
     *  saved up, this is done in case of user returning 
     *  back from the contact detail screen
     */
    setListAdapter(adapter);
      if(index!=-1){
         this.getListView().setSelectionFromTop(index, top);
      }
}

希望这会有所帮助!

【讨论】:

  • 谢谢!,我会使用这种方法,但前提是有人告诉我以我发布的方式重用视图是错误的
【解决方案2】:

如果您在执行删除片段的事务时不调用 addToBackStack(),则在提交事务并且用户无法导航回该片段时,该片段将被销毁。然而,如果您在移除片段时确实调用了 addToBackStack(),那么片段将停止,并且如果用户导航回来,它将恢复。

提示:对于每个片段事务,您可以应用一个转换 动画,在你提交之前调用 setTransition()。

调用 commit() 不会立即执行事务。相反,一旦线程能够这样做,它就会安排它在活动的 UI 线程(“主”线程)上运行。但是,如有必要,您可以从 UI 线程调用 executePendingTransactions() 以立即执行由 commit() 提交的事务。除非事务是其他线程中作业的依赖项,否则通常不需要这样做。

【讨论】:

    猜你喜欢
    • 2023-03-28
    • 2011-08-18
    • 2011-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多