【问题标题】:FragmentManager.popBackStack() does not simply loads the previous FragmentFragmentManager.popBackStack() 不会简单地加载之前的 Fragment
【发布时间】:2012-04-01 14:55:34
【问题描述】:

我有一个主 TabActivity,它有两个选项卡,A 和 B(目前)。 Tab A 加载了一个 FragmentActivity(代码如下),它只包含一个 FrameLayout,所以我可以为其中的特定 Tab 加载我的 Fragments。

第一个 Fragment 有一些 TextView 和一个 ListView。数据是从 Web 服务中提取的。当我单击 ListView 的项目时,我会将该项目的详细信息加载到另一个 Fragment(这也来自 Web 服务)中,并用另一个详细信息 Fragment 替换当前的 Fragment(带有 ListView 和其他控件)。

为了实现这一点,我使用 android-support-v4.jar 库来使用 Fragments,因为它们是首选。

Tab A 的 FragmentActivity 的 XML:

<?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >

        <FrameLayout
            android:id="@+id/updates_frame"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:background="@drawable/background"/>
    </LinearLayout>

Tab A 的 FragmentActivity Java 代码:

public class UpdatesFragmentActivity extends FragmentActivity implements
    IUpdateNotifier {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.updates);

        //Load Initial Fragment into FrameLayout
        //I am adding this Fragment to BackStack
        Fragment newFragment = new UpdatesFragment();
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.addToBackStack(null);
        ft.add(R.id.updates_frame, newFragment);
        ft.commit();
    }

    //This is an Interface method which I call with the clicked "FEED" object to load its detail in another Fragment
    @Override
    public void onFeedSelected(Feed feed) {
        // Instantiate a new fragment.
        Fragment newFragment = new FeedDetailFragment(feed);

        // Add the fragment to the activity, pushing this transaction
        // on to the back stack.
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.replace(R.id.updates_frame, newFragment);
        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
        ft.addToBackStack(null);
        ft.commit();
    }

    //This is another Interface Method which I call when the user presses "BACK".
    //I am trying to load the previously loaded Fragment, which I added to BackStack.
    //But this causes reconstruction of the previously loaded fragment. LIST in this case
    //which call the web service. I DONT WANT TO CALL SERVICE AGAIN.
    @Override
    public void onBackPressed() {
        FragmentManager fm = getSupportFragmentManager();
        if (fm.getBackStackEntryCount() > 0) {
            fm.popBackStack();
        }
    }
}

我创建了一个接口IUpdateNotifier,其中包含两个方法:

public void onFeedSelected(Feed feed);
public void onBackPressed();

UpdatesFragmentActivity 实现这些方法。在执行以下操作时,我将这些方法从子片段中调用。

  1. 我从具有 ListView 的 Fragment 调用 onFeedSelected(Feed feed)。我将点击的提要项发送到父 FragmentActivity,因此它会加载另一个包含该提要详细信息的 Fragment。
  2. 当用户按下一个按钮时,我从第二个提要详细信息片段中调用 onBackPressed(),该按钮应该带回包含 ListView 和其他控件的第一个片段。如您所见,我尝试调用 FragmentManager 的 popBackStack() 方法来恢复第一个 Fragment...

但第一个 Fragment 会刷新并从 Web 服务加载所有数据。

实际上,我不能只获取和存储一次数据,也不能在某些时间间隔内频繁更新。用户可以在需要时更新列表。最初,列表会加载服务中排名前 10 的项目,然后如果用户想要加载更多项目,可以单击列表末尾的“更多”按钮。

它将加载接下来的 10 个项目,依此类推。但我认为我可以将检索到的 ArrayList 存储在 UpdatesFragmentActivity 中的某个变量中,然后将该 ArrayList 重新分配给列表的适配器,而不是从服务中加载数据,但我不知道如何使 Fragment 不再次致电服务。

我希望它的行为类似于我单击选项卡 2,然后再次单击选项卡 1。它只是将加载的数据显示为隐藏,并且不调用服务。

我怎样才能做到这一点?

【问题讨论】:

  • 你有解决办法吗

标签: android android-listview android-fragments


【解决方案1】:

由于关注点分离不佳,您的设计模式存在缺陷。数据的更新应该与 UI 解耦,因此当用户返回之前的 Fragment 时,应该与从 Web 服务加载数据无关。

有几个简单的修复方法,但我不知道哪种方法最有效,因为您没有给出问题的背景信息。

第一个选项是在启动时引入启动画面。此活动将使用AsyncTask 从 Web 服务下载您需要的数据。如果您只想在应用程序运行期间下载一次数据,这很有效。您将确保不要将此 Activity 添加到历史记录中,这样当从下一个 Activity 按下返回时,应用程序就会退出。

另一个选项,我在许多应用程序中使用过并且我更喜欢的选项是通过AlarmManager 使用警报。您可以在特定的时间间隔设置定期更新,AlarmManager 甚至可以帮助您到达包含时间枚举的点。警报将触发broadcast receiver,它将执行您的自定义代码,从网络服务下载您需要的数据并存储。

有一个关于这种方法的教程,可以在这里找到http://android.arnodenhond.com/tutorials/alarm-notification

最后;您不需要弹出返回堆栈来解决此问题,尽管您可能出于完全不同的原因这样做,但如果没有更多信息很难判断。

【讨论】:

  • 我很抱歉没有就我所面临的问题提供足够的信息。我已经更新了我的问题......你现在可以看看它......我试图解释我的问题。
  • 我不会改变我的答案,因为我不同意你选择了最好的方法。上面的答案应该会引导你朝着正确的方向前进。
  • 实际上我不能只获取和存储数据一次,也不能在某些时间间隔内频繁更新,用户可以在需要时更新列表。最初列表从服务中加载前 10 个项目,然后如果他想加载更多项目,用户可以单击列表末尾的“更多”按钮。它将加载接下来的 10 个项目..等等。我很感激你向我指出了 AlarmManager,我可能会在需要定期更新的某些场景中使用它,但我认为我不能在这种情况下使用 AlarmManager。但我认为我可以将检索到的 ArrayList 存储在 FragmentActivity 中的某个变量中。
  • 然后只需将该 ArrayList 重新分配给列表的适配器,而不是从服务加载数据......但我不知道如何让 Fragment 不再调用服务。当我陷入困境时,您可以帮助我实现这一目标..如果您现在了解我的情况,那么您可以指导我采取一些最佳方法。我真的很感激,因为我是 android 新手。谢谢
  • 没有。永远不要使用AlarmManager 来安排仅在显示某个片段时才重要的定期重复任务。请参阅developer.android.com/reference/android/app/AlarmManager.html 上的文档
【解决方案2】:

你的问题不够清楚,问更简单准确的问题……正如你上面所说的

popBackStack 不加载最后一个片段,它通常用于弹出整个堆栈:

fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); 

在加载另一个片段之前

beginTransaction()
replace() Or add()
commit()

这就是我能想到的问题

祝你好运

【讨论】:

  • 我的解决方案是 fragmentManager.popBackStack(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-16
  • 2016-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-16
相关资源
最近更新 更多