FragmentManager.popBackStack()不会简单地加载前一个Fragment

时间:2012-04-01 14:55:34

标签: android android-listview android-fragments

我有一个主 TabActivity ,它有两个标签,A和B(现在)。选项卡A加载FragmentActivity(下面给出的代码),它只包含FrameLayout,因此我可以为其中的特定选项卡加载我的片段。

第一个Fragment有一些TextViews和一个 ListView 。数据来自Web服务。当我单击ListView的项目时,我将该项目的详细信息加载到另一个片段中(这也来自Web服务)并将当前片段(使用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. 我从片段中调用 onFeedSelected(Feed feed),其中包含 ListView 。我将点击的Feed项发送到父FragmentActivity,因此它会加载另一个包含该Feed详细信息的Fragment。
  2. 当用户按下一个按钮时,我会从第二个Feed详细信息Fragment中调用 onBackPressed(),该按钮应该将包含ListView的第一个片段带回其他控件。正如您所看到的,我尝试调用 FragmentManager的popBackStack()方法来恢复第一个片段......
  3. 但第一个Fragment会刷新并加载来自Web服务的所有数据。

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

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

    我希望它的行为就像我点击标签2然后再次点击标签1一样。它只是将加载的数据显示为隐藏,并且不会调用服务。

    我怎样才能做到这一点?

2 个答案:

答案 0 :(得分:4)

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

有几个简单的修复,但我不知道什么会最好,因为你没有给出问题的背景。

第一个选择是在启动时引入启动画面。此活动将使用AsyncTask从Web服务下载所需的数据。如果您只希望在应用程序运行时期间下载一次数据,则此方法很有效。您将确保不将此活动添加到历史记录中,因此当从下一个活动中按下后退时,应用程序将退出。

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

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

最后;你不应该弹出后面的堆栈来解决这个问题,虽然你可能会因为完全不同的原因而这样做,但是如果没有更多的信息就很难说。

答案 1 :(得分:2)

你的问题不够明确,请问更简单准确的问题......正如你上面所说的

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

fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); 

在加载另一个片段之前

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

这就是我能用这个问题思考的全部内容

祝你好运