【问题标题】:popBackStack causes calling oncreateView of fragment again and againpopBackStack导致一次又一次调用片段的oncreateView
【发布时间】:2014-04-12 06:47:58
【问题描述】:

我有 3 个片段 A、B、C。我写了一段代码来替换它们并维护 backstack:

 public void addFragment(Fragment fragmentToAdd, String fragmentTag) {
        FragmentManager supportFragmentManager = getSupportFragmentManager();
        Fragment activeFragment = getActiveFragment();
        FragmentTransaction fragmentTransaction = supportFragmentManager
                .beginTransaction();
        if (null != activeFragment) {
            fragmentTransaction.hide(activeFragment);
        }
        fragmentTransaction.replace(R.id.layout_child_activity, fragmentToAdd,
                fragmentTag);

       if (supportFragmentManager.getBackStackEntryCount() > 1) {
            supportFragmentManager.popBackStack();
        }
        fragmentTransaction.addToBackStack(fragmentTag);
        fragmentTransaction.commit();
    }

在这段代码中

if (supportFragmentManager.getBackStackEntryCount() > 1) {
    supportFragmentManager.popBackStack();
}

如果堆栈长度大于 1,我会使用弹出最新片段。现在由于这个原因,当长度大于 1 时,它会一次又一次地调用 onCreate 视图。 喜欢:

  1. 打开 A.
  2. 打开 B.
  3. 打开C.(如果打开C.调用A的onCreateView。)

为什么我会出现这种行为?当我删除该斜体代码时,它不会发生。

【问题讨论】:

  • 您能否详细说明您想通过使用该代码实现什么?
  • @Szymon 我想在抽屉中的片段之间切换并保持回栈长度为 1。
  • 你找到解决这个问题的办法了吗?

标签: android android-fragments fragment back-stack fragmentmanager


【解决方案1】:

正如文档所说,来自后台事务的行为是正常的。 backstack 从不保存 Fragments,它只是保存事务

http://developer.android.com/intl/es/guide/components/fragments.html

我所做的,我不确定是否是最好的方法,但是 当我想清除所有交易时,我会这样做

1) 在您的 Activity 中检查后台堆栈中是否有任何交易, 并在您的片段中添加一个标志,在您的情况下是 A

       int backStackCount = getSupportFragmentManager().getBackStackEntryCount();

       if(backStackCount > 0) {
           Transactions.MUST_DETACH_FROM_BACKSTACK = true;
           getSupportFragmentManager().popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
       }

2) 在您的片段 A 中,获取标志并删除片段 onCreateView 并像这样返回 null

public class Transactions extends android.support.v4.app.Fragment{

public static boolean MUST_DETACH_FROM_BACKSTACK = false;

public Transactions() {
    // Required empty public constructor
}


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    Log.i("FRAGMENT", "onCreateView "+MUST_DETACH_FROM_BACKSTACK);
    // Inflate the layout for this fragment
    if (MUST_DETACH_FROM_BACKSTACK) {
        MUST_DETACH_FROM_BACKSTACK = false;
        getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();
        return null;
    }
    return inflater.inflate(R.layout.fragment_transactions, container, false);
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);


    Log.i("FRAGMENT", "onViewCreated");
    if(view != null){

        Log.i("FRAGMENT", "ThreadStarted");
        startThread(view);
    }
}

但要小心,我在 onResume() 之后调用了

OnCreateView()

即使使用 getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();

所以如果你有任何 conde onResume 方法你应该正确处理它

【讨论】:

    【解决方案2】:

    我通过从我的自定义 BaseFragment (2) 继承 (1) 所有片段解决了这个问题。 在这个 BaseFragment 中,我创建了一个变量: public static boolean removal; (3) 并在调用 popBackStackImmediate() 之前将其设置为 true (4),然后将其重置为 false。 (5) 在 BaseFragment-childs 我检查变量。 (6)

    示例代码

    活动类

        BaseFragment.removing = true; //(4)
        //pop all fragments
        while(getSupportFragmentManager().getBackStackEntryCount() > 0){
            fragmentManager.popBackStackImmediate();
        }
        BaseFragment.removing = false; //(5)
    

    BaseFragment (2)

    public class BaseFragment extends Fragment{
       public static boolean removing = false; //(3)
    }
    

    片段-孩子

    public class fragment extends BaseFragment{ //(1)
      @Override
      public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
          if(!removing){ // (6)
              //your code
          }
      }
    }
    

    【讨论】:

      【解决方案3】:

      记住fragment 的生命周期。当我们回到这一点时,它将始终从oncreateView() 开始。但是我们仍然可以保存数据,然后我们将在 oncreated 中处理这些数据以填充我们的视图。你可以这样做:

      Main-activity.java

      public class MainActivity extends AppCompatActivity implements Fragment2.myListener {
      private static final String TAG = "MainActivity";
      
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          Log.e(TAG, "onCreate: ");
          setContentView(R.layout.activity_main);
      
          Button button = (Button) findViewById(R.id.button);
          button.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View view) {
                  Fragment1 fragment1 = Fragment1.newInstance();
                  FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
                  fragmentTransaction.replace(R.id.fragmentContainer, fragment1, Fragment1.TAG);
                  fragmentTransaction.addToBackStack(Fragment1.TAG);
                  fragmentTransaction.commit();
              }
          });
      
      }
      
      @Override
      public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
          super.onSaveInstanceState(outState, outPersistentState);
          Log.e(TAG, "onSaveInstanceState");
      }
      
      @Override
      protected void onDestroy() {
          super.onDestroy();
          Log.e(TAG, "onDestroy");
      }
      
      @Override
      public void bindCount(int newCount) {
          ((Fragment1)getSupportFragmentManager().findFragmentByTag(Fragment1.TAG)).setCount(newCount);
      }
      

      }

      Fragment1.java

      public class Fragment1 extends Fragment {
      public static final String TAG = "fragment1";
      private static final String SAVE_COUNT = "save_count";
      
      private int count;
      
      public Fragment1() {
      }
      
      public static Fragment1 newInstance() {
          Fragment1 fragment = new Fragment1();
          return fragment;
      }
      
      @Override
      public void onCreate(@Nullable Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          Log.e(TAG, "onCreate: ");
          if (savedInstanceState != null) {
              count = savedInstanceState.getInt(SAVE_COUNT);
          }
      }
      
      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container,
                               Bundle savedInstanceState) {
      
          View view =  inflater.inflate(R.layout.fragment_fragment1, container, false);
      
      
          Button goToButton = (Button) view.findViewById(R.id.button);
          goToButton.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View view) {
                  Fragment2 fragment2 = Fragment2.newInstance();
                  FragmentTransaction fragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
                  fragmentTransaction.replace(R.id.fragmentContainer, fragment2, Fragment2.TAG);
                  fragmentTransaction.addToBackStack(Fragment2.TAG);
                  fragmentTransaction.commit();
              }
          });
      
          return view;
      }
      
      public  void setCount(int newCount){
          count = newCount;
      }
      
      @Override
      public void onSaveInstanceState(Bundle outState) {
          super.onSaveInstanceState(outState);
          Log.e(TAG, "onSaveInstanceState: ");
          outState.putInt(SAVE_COUNT, count);
      }
      

      }

      Fragment2.java

      public class Fragment2 extends Fragment {
      public static final String TAG = "fragment2";
      
      public Fragment2() {
          // Required empty public constructor
      }
      
      public static Fragment2 newInstance() {
          Fragment2 fragment = new Fragment2();
      
          return fragment;
      }
      
      myListener listener;
      
      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container,
                               Bundle savedInstanceState) {
      
          View view = inflater.inflate(R.layout.fragment_fragment2, container, false);
          //Here I am just modifying a value that wants to send to fragment1
          listener.bindCount(45);//newCount
      
          return view;
      }
      
      public interface myListener{
          void bindCount(int newCount);
      }
      
      @Override
      public void onActivityCreated(@Nullable Bundle savedInstanceState) {
          super.onActivityCreated(savedInstanceState);
          //initialice listener
          listener = (myListener) getActivity();
      }
      

      }

      所以...对于fragments 之间的通信,我们将需要您的容器activity,通过接口。正如我们所见,Fragment2 有一个interface,它实现了它的activity,当它执行时,它调用了一个方法,我们改变fragment1 中的计数值,它存储在onSaveInstanceState 中,所以我们可以恢复即使再次执行oncreateview,也会发生任何修改。这可以用于许多其他数据,例如arraylist, string, float, long, object, 等。

      对不起我的“英语”!!!!!!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多