Android Fragment,无需重新创建/重新加载Fragment即可返回

14

我在SO上看到了很多关于Fragment的问题,但我仍然无法弄清楚我想做的事情是否可行,更重要的是,我的设计模式是否有缺陷并且需要重新制定整个流程。基本上,就像已经提出的大多数问题一样,我有一个带有导航选项卡的ActionBar(使用ActionBarSherlock),然后在每个选项卡中有一个FragmentActivity,当选择一行时,FragmentActivities会推送新的Fragments(我正在尝试在Android中重新创建一个iOS项目,它只是一个基本的基于导航的应用程序,其中某些选项卡可以深入到特定信息中)。当我点击手机上的返回按钮时,会加载上一个Fragment,但该Fragment会重新创建(因此对于每个视图都会再次调用WebServices),这是不必要的,因为在向后移动时先前视图中的信息不会更改。所以基本上,我想弄清楚的是,如何设置我的Fragments,以便在按下手机的返回按钮时,只需拉起先前的Fragment,并已经创建好了旧的项。以下是我的当前代码:

    //This is from my FragmentActivity Class that contains the ActionBar and Tab Selection Control
    @Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
    // TODO Auto-generated method stub
    int selectedTab = tab.getPosition();

    if (selectedTab == 0) {
        SalesMainScreen salesScreen = new SalesMainScreen();
        ft.replace(R.id.content, salesScreen);
    }
    else if (selectedTab == 1) {
        ClientMainScreen clientScreen = new ClientMainScreen();
        ft.replace(R.id.content, clientScreen);
    }.....

   //This is within the ClientMainScreen Fragment Class, which handles moving to the Detail Fragment
   row.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            //Do something if Row is clicked
                            try{
                                String selectedClientName = clientObject.getString("ClientName");
                                String selectedClientID = clientObject.getString("ClientID");
                                String selectedValue = clientObject.getString("ClientValue");
                                transaction = getFragmentManager().beginTransaction();
                                ClientDetailScreen detailScreen = new ClientDetailScreen();
                                detailScreen.clientID = selectedClientID;
                                detailScreen.clientName = selectedClientName;
                                detailScreen.clientValue = selectedValue;
                                int currentID = ((ViewGroup)getView().getParent()).getId();
                                transaction.replace(currentID,detailScreen);
                                transaction.addToBackStack(null);
                                transaction.commit();

                            }
                            catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    });....

     //And then this is the Client Detail Fragment, with the method being called to Call the Web Service and create thew (since what is displayed on this screen is dependent on what is found in the Web Service
          @Override
public View onCreateView(LayoutInflater inflater, ViewGroup group, Bundle saved) {
    return inflater.inflate(R.layout.clientdetailscreen, group, false);
}

@Override
public void onActivityCreated (Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    //Setup Preferences File Link
    this.preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());

    //initialize the table object
    mainTable = (TableLayout)getActivity().findViewById(R.id.mainTable);

    //setup the detail table
    setupRelatedClientSection();

}

客户详细信息屏幕可以再次进行深入,使用与客户主屏幕相同的方法,但是当我从那个新屏幕返回到详细信息屏幕时,seuptRelatedClientSection() 方法再次被调用,因此整个片段被重建,而我只想打开保存的版本。我的当前设置是否支持这种可能性,还是我方法有误?

4个回答

13

尝试使用fragementTransaction.add而不是replace


7

我相信您正在寻找show()hide()函数。

我认为您仍然可以将它们添加到后退栈中。

 transaction.hide(currentFragment);
 transaction.show(detailScreen);
 transaction.addToBackStack(null);
 transaction.commit();

我没有代码可以查看,但我相信这是正确的方法... 除非有更好的方法,否则请尝试一下。 我还没有使用show() hide()尝试过backstack,但我认为它会在事务提交之前保存所做的更改,并在按下后退按钮时撤消它们。因为我很感兴趣,请回复我以了解更多信息。
您还需要确保在调用此函数之前创建了详细信息片段。由于它基于某些项目的单击,因此您应该每次单击时创建详细信息片段,以确保创建了正确的详细信息片段。

5
我使用了 .add() 而不是 .show()。从第二个片段返回时,它跳转到了第一个片段而没有刷新。 - Sri

5
我为可能在未来参考此问题的人们发布此答案。
以下代码将演示如何从FragmentA打开FragmentB,并通过按返回按钮从FragmentB返回到FragmentA(而不刷新FragmentA)。
public class FragmentA extends Fragment{

   ...

   void openFragmentB(){

       FragmentManager fragmentManager = 
           getActivity().getSupportFragmentManager();
       FragmentB fragmentB = FragmentB.newInstance();

       if (fragmentB.isAdded()) {

           return;
       } else {

           fragmentManager.
               beginTransaction().
               add(R.id.mainContainer,fragmentB).
               addToBackStack(FragmentB.TAG).
               commit();
      }
   }
}

public class FragmentB extends Fragment{

    public static final String TAG = 
        FragmentB.class.getSimpleName();

    ...

    public static FragmentB newInstance(){

        FragmentB fragmentB = new FragmentB();
        return fragmentB;
    }

    @Override
    public void onResume() {

        super.onResume();
        // add this piece of code in onResume method
        this.getView().setFocusableInTouchMode(true);
        this.getView().requestFocus();
    }
}

在你的MainActivity中重写onBackPressed()方法。
class MainActivity extends Activity{
    ...

    @Override
    public void onBackPressed() {

        if (getFragmentManager().getBackStackEntryCount() > 0) {

            getFragmentManager().popBackStack();
        } else {

            super.onBackPressed();
        }
    } 
}

0

你说得对,之前已经有一些关于这个主题的问题/文档了;)

关于片段的文档,特别是有关事务和保存状态的部分,将指导您找到答案。

http://developer.android.com/guide/components/fragments.html#Transactions

http://developer.android.com/guide/components/activities.html#SavingActivityState

Android - Fragment onActivityResult avoid reloading

片段可以支持onSaveInstanceState,但不支持onRestoreInstanceState,因此如果您想保存对表视图的引用,请将它们保存到Bundle中,并且您可以在onActivityCreated方法中访问保存的视图。您还可以使用片段返回堆栈。

本指南/教程提供了有关返回堆栈和保留片段状态的非常详细的说明/示例。

祝你好运!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接