如何从BackStack恢复片段是否存在 [英] How to resume Fragment from BackStack if exists

查看:124
本文介绍了如何从BackStack恢复片段是否存在的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您好我使用的片段。我创建的类的前三名实例取值片段和初始化它们。我加入片段与活动是这样的:

Hello I am using Fragment. I have created three instances of Fragment and initialize them at the top of the class. I am adding fragment to an activity like this:

Decalring和初始化:

Decalring and initializing:

Fragment A = new AFragment();
Fragment B = new BFragment();
Fragment C = new CFragment();

更换/添加片段:

Replacing/Adding Fragment:

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, A);
ft.addToBackStack(null);
ft.commit();

这些片段是否工作正常。而每一个片段连接上的活动,并保存到 backStack 成功。

These snippets are working properly. And every Fragment is attached on activity and saved to backStack successfully.

所以,当我启动 A ,然后启动 C ,然后启动 B ,堆栈变得

So when I launch A and then launch C and then launch B, the stack becomes

| |
|B|
|C|
|A|
___

当我preSS后退按钮, B 被破坏和 C 恢复

但是,当我再次启动片段 A ,而不是从backstack恢复,它被添加在backstack顶部

But when I again launch fragment A, instead of resuming from backstack, it is added on the top of the backstack

| |
|A|
|C|
|A|
___

不过,我想要恢复 A 并在其销毁所有片段(如果有的话)。 Actaully我就像活动的deafult backStack行为。所以,我该怎么办呢?

But I want to resume A and destroy all fragments upon it (if any). Actaully I just like the deafult backStack behavior of activity. So how can I do that?

预计:(A应予以恢复,并顶碎片被破坏)

Expected: (A should be resumed and top Fragments are to be destroyed)

| |
| |
| |
|A|
___

编辑:(由一个建议 - C)

这是我的艰难code:

This is my trying code:

private void selectItem(int position) {
        Fragment problemSearch = null, problemStatistics = null;
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction ft = manager.beginTransaction();
        String backStateName = null;
        Fragment fragmentName = null;
        boolean fragmentPopped = false;
        switch (position) {
        case 0:
            fragmentName = profile;
            break;
        case 1:
            fragmentName = submissionStatistics;
            break;
        case 2:
            fragmentName = solvedProblemLevel;
            break;
        case 3:
            fragmentName = latestSubmissions;
            break;
        case 4:
            fragmentName = CPExercise;
            break;
        case 5:
            Bundle bundle = new Bundle();
            bundle.putInt("problem_no", problemNo);
            problemSearch = new ProblemWebView();
            problemSearch.setArguments(bundle);
            fragmentName = problemSearch;
            break;
        case 6:
            fragmentName = rankList;
            break;
        case 7:
            fragmentName = liveSubmissions;
            break;
        case 8:
            Bundle bundles = new Bundle();
            bundles.putInt("problem_no", problemNo);
            problemStatistics = new ProblemStatistics();
            problemStatistics.setArguments(bundles);
            fragmentName = problemStatistics;
        default:
            break;
        }
        backStateName = fragmentName.getClass().getName();
        fragmentPopped = manager.popBackStackImmediate(backStateName, 0);
        if (!fragmentPopped) {
            ft.replace(R.id.content_frame, fragmentName);
        }
        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
        ft.addToBackStack(backStateName);
        ft.commit();

        // I am using drawer layout
        mDrawerList.setItemChecked(position, true);
        setTitle(title[position]);
        mDrawerLayout.closeDrawer(mDrawerList);
    }

现在的问题是 - 当我启动 A 然后 B ,然后preSS后退按钮, B 被删除, A 恢复。和pressing再次后退按钮应退出该应用程序。但它显示一个空白窗口,需要另一个preSS将其关闭。

The problem is - when i launch A and then B, then press back button, B is removed and A is resumed. and pressing again back button should exit the app. But it is showing a blank window and need another press to close it.

此外,当我启动 A ,然后 B ,然后 C ,然后再次 B , 预计:

Also when I launch A, then B, then C and then again B, expected:

| |
| |
|B|
|A|
___

但它显示为:

But it is showing as:

| |
|B|
|B|
|A|
___

HOULD我重写 onBack pressed()与任何定制还是我失去了什么?

hould I override onBackPressed() with any customization or am I missing anything?

推荐答案

读<一href="http://developer.android.com/reference/android/support/v4/app/FragmentManager.html">documentation,有一种方法,以弹出根据任一事务名称或通过提交提供的ID背面栈。使用名称的可以的更容易,因为它不应该需要跟踪的数量可能会改变和强化了独特的回堆栈入口逻辑。

Reading the documentation, there is a way to pop the back stack based on either the transaction name or the id provided by commit. Using the name may be easier since it shouldn't require keeping track of a number that may change and reinforces the "unique back stack entry" logic.

由于您希望每片段只一回堆栈条目,让背部州名片段的类名(通过的getClass()。的getName( ))。然后更换当片段,使用<一个href="http://developer.android.com/reference/android/support/v4/app/FragmentManager.html#popBackStackImmediate%28java.lang.String,%20int%29"><$c$c>popBackStackImmediate()方法。如果返回true,这意味着这些片段在后面堆栈的实​​例。如果不是这样,实际执行的片段更换逻辑。

Since you want only one back stack entry per Fragment, make the back state name the Fragment's class name (via getClass().getName()). Then when replacing a Fragment, use the popBackStackImmediate() method. If it returns true, it means there is an instance of the Fragment in the back stack. If not, actually execute the Fragment replacement logic.

private void replaceFragment (Fragment fragment){
  String backStateName = fragment.getClass().getName();

  FragmentManager manager = getSupportFragmentManager();
  boolean fragmentPopped = manager.popBackStackImmediate (backStateName, 0);

  if (!fragmentPopped){ //fragment not in back stack, create it.
    FragmentTransaction ft = manager.beginTransaction();
    ft.replace(R.id.content_frame, fragment);
    ft.addToBackStack(backStateName);
    ft.commit();
  }
}


修改

现在的问题是 - 当我启动A,然后B,然后preSS后退按钮,B   被删除,重新开始。和pressing再次后退按钮应   退出该应用程序。但它显示一个空白窗口,需要另一个preSS   将其关闭。

The problem is - when i launch A and then B, then press back button, B is removed and A is resumed. and pressing again back button should exit the app. But it is showing a blank window and need another press to close it.

这是因为 FragmentTransaction 被添加到后退堆栈,以确保我们能弹出的碎片之上后。这样做的一个速战速决的覆盖 onBack pressed()和整理活动,如果后面堆栈只包含1 片段

This is because the FragmentTransaction is being added to the back stack to ensure that we can pop the fragments on top later. A quick fix for this is overriding onBackPressed() and finishing the Activity if the back stack contains only 1 Fragment

@Override
public void onBackPressed(){
  if (getSupportFragmentManager().getBackStackEntryCount() == 1){
    finish();
  }
  else {
    super.onBackPressed();
  }
}

对于重复的回堆栈条目,你替换片段条件语句,如果它没有被弹出很明显的不同的的比我原来的code段的。你在做什么也加入到了后面堆不管后面堆栈是否被弹出。

Regarding the duplicate back stack entries, your conditional statement that replaces the fragment if it hasn't been popped is clearly different than what my original code snippet's. What you are doing is adding to the back stack regardless of whether or not the back stack was popped.

像这样的东西应该更接近你想要的:

Something like this should be closer to what you want:

private void replaceFragment (Fragment fragment){
  String backStateName =  fragment.getClass().getName();
  String fragmentTag = backStateName;

  FragmentManager manager = getSupportFragmentManager();
  boolean fragmentPopped = manager.popBackStackImmediate (backStateName, 0);

  if (!fragmentPopped && manager.findFragmentByTag(fragmentTag) == null){ //fragment not in back stack, create it.
    FragmentTransaction ft = manager.beginTransaction();
    ft.replace(R.id.content_frame, fragment, fragmentTag);
    ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
    ft.addToBackStack(backStateName);
    ft.commit();
  } 
}

的条件是因为选择相同的片段,而这是看得见也造成重复条目修改一下。

The conditional was changed a bit since selecting the same fragment while it was visible also caused duplicate entries.

执行:

我强烈建议不要采取更新的 replaceFragment()方法除了像你在code一样。所有的逻辑被包含在此的方法和移动部件周围可能会引起问题。

I highly suggest not taking the the updated replaceFragment() method apart like you did in your code. All the logic is contained in this method and moving parts around may cause problems.

这意味着你应该复制更新 replaceFragment()方法到类然后更改

This means you should copy the updated replaceFragment() method into your class then change

backStateName = fragmentName.getClass().getName();
fragmentPopped = manager.popBackStackImmediate(backStateName, 0);
if (!fragmentPopped) {
            ft.replace(R.id.content_frame, fragmentName);
}
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(backStateName);
ft.commit();

所以它只是

replaceFragment (fragmentName);


编辑#2

要更新的抽屉时,后面的堆栈的变化,使该接受的片段,并比较了类名的方法。如果有任何匹配,更改标题和选择。还添加了一个 OnBackStackChangedListener 并调用它的更新方法,如果有一个有效的片段。

To update the drawer when the back stack changes, make a method that accepts in a Fragment and compares the class names. If anything matches, change the title and selection. Also add an OnBackStackChangedListener and have it call your update method if there is a valid Fragment.

例如,在活动的的onCreate()添加

getSupportFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener() {

  @Override
  public void onBackStackChanged() {
    Fragment f = getSupportFragmentManager().findFragmentById(R.id.content_frame);
    if (f != null){
      updateTitleAndDrawer (f);
    }

  }
});

和另一种方法:

private void updateTitleAndDrawer (Fragment fragment){
  String fragClassName = fragment.getClass().getName();

  if (fragClassName.equals(A.class.getName())){
    setTitle ("A");
    //set selected item position, etc
  }
  else if (fragClassName.equals(B.class.getName())){
    setTitle ("B");
    //set selected item position, etc
  }
  else if (fragClassName.equals(C.class.getName())){
    setTitle ("C");
    //set selected item position, etc
  }
}

现在,每当回栈变化,标题,并检查位置将反映可见片段

Now, whenever the back stack changes, the title and checked position will reflect the visible Fragment.

这篇关于如何从BackStack恢复片段是否存在的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆