popBackStack causes calling oncreateView of fragment again and again

后端 未结 3 1793
孤城傲影
孤城傲影 2021-02-19 04:40

I have 3 fragment A, B,C.I wrote piece of code for replacing them and maintaining backstack:

 public void addFragment(Fragment fragmentToAdd, String fragmentTag)         


        
相关标签:
3条回答
  • 2021-02-19 04:48

    Remember the life cycle of a fragment. By the time we get back to this, it will start from oncreateView() always. But we can still save data that we will then process in the oncreated to fill our view. for you you can do that:

    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();
    }
    

    }

    So ... For the communication between fragments we will need your container activity, through interface. As we can see, Fragment2 has an interface that implements its activity and when it is executed, it calls a method where we change the count value in fragment1, which is stored in onSaveInstanceState, so we can resume any modification that occurs even when oncreateview is executed again. this can be used for many other data such as arraylist, string, float, long, object, etc.

    sorry my "english"!!!!!

    0 讨论(0)
  • 2021-02-19 05:06

    Than behavior is normal, coming from the backstack transaction, as the docs say. The backstack never saves Fragments, it just saves the transaction

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

    What I do, I am not sure if, is it the best way but when I want to clear all the transactions I do this

    1) INSIDE YOUR ACTIVITY check if is there any transactions in the back stack, and add a flag inside your fragment, in your case is A

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

    2) Inside your fragment A, get the flag and Remove the fragment onCreateView and return null like this

    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);
        }
    }
    

    BUT BE CAREFULL I Get onResume() Called after the

    OnCreateView()
    

    even with getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();

    So if you have any conde onResume method you should handle it properly

    0 讨论(0)
  • 2021-02-19 05:06

    I solved this problem by inheriting (1) all fragments from my custom BaseFragment (2). In this BaseFragment I created a variable: public static boolean removing; (3) and set it to true (4) before calling popBackStackImmediate() and reset it to false after that. (5) In the BaseFragment-childs I check the variable. (6)

    Example-Code

    Activity-class

        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
          }
      }
    }
    
    0 讨论(0)
提交回复
热议问题