popBackStack导致一次又一次地调用片段的oncreateView

时间:2014-03-09 04:59:24

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

我有3个片段A,B,C.我写了一段代码来替换它们并维护后台堆栈:

 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的onCreateView,则会被调用。)
  4. 为什么我会遇到这种行为?当我删除斜体代码而不是没有发生时。

3 个答案:

答案 0 :(得分:5)

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

enter image description here

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

我做什么,我不确定它是否是最好的方式,但是 当我想清除我做的所有交易时

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

       int backStackCount = getSupportFragmentManager().getBackStackEntryCount();

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

2)在你的片段A中,获取标志并删除fragent 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方法,你应该正确地处理它

答案 1 :(得分:0)

我通过继承(1)我自定义BaseFragment的所有片段(2)解决了这个问题。 在这个BaseFragment中,我创建了一个变量:public static boolean removeing; (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)
}

Fragment-Child

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

答案 2 :(得分:0)

enter image description here

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

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的{​​{1}},当它执行时,它调用一个方法,在其中我们更改activity中的计数值,该计数值存储在{{ 1}},因此即使重新执行fragment1,我们也可以继续进行任何修改。可以用于许多其他数据,例如onSaveInstanceState等。

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