0

I'm learning to use the fragments and I met some problems about replace and remove methods. Here is my activity class:

public class MainActivity extends AppCompatActivity implements BlankFragment.OnFragmentInteractionListener {
private BlankFragment fragment1;
private BlankFragment fragment2;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
    fragment1 = BlankFragment.newInstance("Fragment 1","");
    fragmentTransaction.add(R.id.linearLayout,fragment1);
    fragmentTransaction.commit();

}
public void onClick(View arg0)
{
    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

    switch (arg0.getId())
    {

        case R.id.button:
            fragment2 = BlankFragment.newInstance("Fragment 2", "");
            fragmentTransaction.add(R.id.linearLayout, fragment2);
            fragmentTransaction.commit();
            break;

        case R.id.button2:
            Toast.makeText(this,"REMOVE",Toast.LENGTH_SHORT).show();
            if(fragment2!=null)
            {
                fragmentTransaction.remove(fragment2);
                fragmentTransaction.commit();
            }
            break;

        case R.id.button3:
            fragmentTransaction.replace(R.id.linearLayout,fragment2);
            fragmentTransaction.commit();
            break;

    }
}

public void onFragmentInteraction(Uri uri)
{

}
}

Here is the Fragment Class:

public class BlankFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";

// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;

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

/**
 * Use this factory method to create a new instance of
 * this fragment using the provided parameters.
 *
 * @param param1 Parameter 1.
 * @param param2 Parameter 2.
 * @return A new instance of fragment BlankFragment.
 */
// TODO: Rename and change types and number of parameters
public static BlankFragment newInstance(String param1, String param2) {
    BlankFragment fragment = new BlankFragment();
    Bundle args = new Bundle();
    args.putString(ARG_PARAM1, param1);
    args.putString(ARG_PARAM2, param2);
    fragment.setArguments(args);
    return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {
        mParam1 = getArguments().getString(ARG_PARAM1);
        mParam2 = getArguments().getString(ARG_PARAM2);
    }
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View rootView = inflater.inflate(R.layout.fragment_blank, container, false);
    TextView textView =  ((TextView) rootView.findViewById(R.id.textView));
    textView.setText(mParam1);
    return rootView;
}

// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
    if (mListener != null) {
        mListener.onFragmentInteraction(uri);
    }
}

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    if (context instanceof OnFragmentInteractionListener) {
        mListener = (OnFragmentInteractionListener) context;
    } else {
        throw new RuntimeException(context.toString()
                + " must implement OnFragmentInteractionListener");
    }
}

@Override
public void onDetach() {
    super.onDetach();
    mListener = null;
}

/**
 * This interface must be implemented by activities that contain this
 * fragment to allow an interaction in this fragment to be communicated
 * to the activity and potentially other fragments contained in that
 * activity.
 * <p>
 * See the Android Training lesson <a href=
 * "http://developer.android.com/training/basics/fragments/communicating.html"
 * >Communicating with Other Fragments</a> for more information.
 */
public interface OnFragmentInteractionListener {
    // TODO: Update argument type and name
    void onFragmentInteraction(Uri uri);
}
}

Here is the manifest:

<?xml version="1.0" encoding="utf-8"?>

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

</application>

Well, I have 2 fragments. When I click the first button, I want to add the second fragment. If I click this button 10 times, will there be 11 fragments in the back stack (10 fragments number 2 and 1 number 1)? Or only two fragments? When I click the second button, I remove the fragment number 2, if there is, of course. But if I click two or more times the first button, if I click 200 times the second button, the second fragment remains...why? When I click the third button, I want to replace the second fragment with the previous fragment. If I click two or more times the first button, if I click the third button and then the second button, the second fragment doesn't remain...why? If I open the app and I click the third button or I click first the second button and then the third, the app crashes

Here is the logcat

02-07 21:33:31.040 17090-17090/com.example.utente.fragment E/AndroidRuntime: FATAL EXCEPTION: main
                                                                         Process: com.example.utente.fragment, PID: 17090
                                                                         java.lang.IllegalStateException: Could not execute method for android:onClick
                                                                             at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:293)
                                                                             at android.view.View.performClick(View.java:5610)
                                                                             at android.view.View$PerformClick.run(View.java:22265)
                                                                             at android.os.Handler.handleCallback(Handler.java:751)
                                                                             at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                             at android.os.Looper.loop(Looper.java:154)
                                                                             at android.app.ActivityThread.main(ActivityThread.java:6077)
                                                                             at java.lang.reflect.Method.invoke(Native Method)
                                                                             at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
                                                                             at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
                                                                          Caused by: java.lang.reflect.InvocationTargetException
                                                                             at java.lang.reflect.Method.invoke(Native Method)
                                                                             at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288)
                                                                             at android.view.View.performClick(View.java:5610) 
                                                                             at android.view.View$PerformClick.run(View.java:22265) 
                                                                             at android.os.Handler.handleCallback(Handler.java:751) 
                                                                             at android.os.Handler.dispatchMessage(Handler.java:95) 
                                                                             at android.os.Looper.loop(Looper.java:154) 
                                                                             at android.app.ActivityThread.main(ActivityThread.java:6077) 
                                                                             at java.lang.reflect.Method.invoke(Native Method) 
                                                                             at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) 
                                                                             at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) 
                                                                          Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Class java.lang.Object.getClass()' on a null object reference
                                                                             at android.support.v4.app.BackStackRecord.doAddOp(BackStackRecord.java:380)
                                                                             at android.support.v4.app.BackStackRecord.replace(BackStackRecord.java:430)
                                                                             at android.support.v4.app.BackStackRecord.replace(BackStackRecord.java:421)
                                                                             at com.example.utente.fragment.MainActivity.onClick(MainActivity.java:50)
                                                                             at java.lang.reflect.Method.invoke(Native Method) 
                                                                             at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288) 
                                                                             at android.view.View.performClick(View.java:5610) 
                                                                             at android.view.View$PerformClick.run(View.java:22265) 
                                                                             at android.os.Handler.handleCallback(Handler.java:751) 
                                                                             at android.os.Handler.dispatchMessage(Handler.java:95) 
                                                                             at android.os.Looper.loop(Looper.java:154) 
                                                                             at android.app.ActivityThread.main(ActivityThread.java:6077) 
                                                                             at java.lang.reflect.Method.invoke(Native Method) 
                                                                             at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) 
                                                                             at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) 

If I click the first button and then the third, the app doesn't crash...why? Where are the errors? The buttons aren't in the fragments but in the activity

Curio
  • 1,331
  • 2
  • 14
  • 34

2 Answers2

1

First of all, check out this post.

Well, I have 2 fragments. When I click the first button, I want to add the second fragment. If I click this button 10 times, will there be 11 fragments in the back stack (10 fragments number 2 and 1 number 1)? Or only two fragments?

If you want to add the transaction to the back stack, add

fragmentTransaction.addToBackStack(null);

before you commit the transaction. Then you can later use popBackStack() on the FragmentManager.

When I click the second button, I remove the fragment number 2, if there is, of course. But if I click two or more times the first button, if I click 200 times the second button, the second fragment remains...why?

This is because when you click the first button, you set fragment2 to a new instance of the fragment, even if it already is one, and thus losing the reference to the old one.

Every time you press the second button after you have pressed the first button two times, it will try to remove the latest created fragment every time. Therefore it will always show the second latest fragment you created, which will always be "Fragment 2".

When I click the third button, I want to replace the second fragment with the previous fragment. If I click two or more times the first button, if I click the third button and then the second button, the second fragment doesn't remain...why?

The replace() method will remove all the previously added fragments and add the one you are trying to add. When you press the third button, you will remove all of the other fragments you have and add fragment2. When you then press the second button it will remove fragment2, and then there is nothing else to show.

If I open the app and I click the third button or I click first the second button and then the third, the app crashes

This is because if you don't press the first button, fragment2 will be null. Pressing the second button will do nothing, since fragment2 is null. Pressing the third button will try to add fragment2, which is null, which then shows the error.

It seems like your second and third button practically is meant to do the same. Maybe reduce it to two buttons, where the first adds a fragment, and the second pops the backstack.

Community
  • 1
  • 1
h3rmanj
  • 128
  • 9
  • it's ok, but I didn't understand why the remove method doesn't remove the fragment when I click two times or more the first button – Curio Feb 08 '17 at 20:57
  • 1
    Lets say when you start the application, you start with fragment n.1, which you have saved in the variable fragment1. When you then press the first button, you get fragment n.2, which is saved in fragment2. Then you press it another time, and then get fragment n.3, which you again save to fragment2. When you press the second button, you remove fragment n.3, and then it shows fragment n.2. When you then press the second button again, it stills try to remove fragment n.3, because you lost the reference to fragment n.2 when you pressed the first button a second time. – h3rmanj Feb 09 '17 at 08:47
0

Remove the onClick() method, you could do it the primary times you do it:

   FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();




    Button button = (Button)findViewById(R.id.button);
    Button button2 = (Button)findViewById(R.id.button2);
    Button button3 = (Button)findViewById(R.id.button3);
    button.setOnClickListener(new View.OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
            fragment2 = BlankFragment.newInstance("Fragment 2", "");
            fragmentTransaction.add(R.id.linearLayout, fragment2);
            fragmentTransaction.commit();
        }
    });

    button2.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) 
        {
            Toast.makeText(this,"REMOVE",Toast.LENGTH_SHORT).show();
            if(fragment2!=null)
            {
                fragmentTransaction.remove(fragment2);
                fragmentTransaction.commit();
            }    
        }
    });

    button3.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) 
        {
            fragmentTransaction.replace(R.id.linearLayout,fragment2);
            fragmentTransaction.commit();    
        }
    });
ste9206
  • 1,822
  • 4
  • 31
  • 47