Search code examples
javaandroidfragmentclasscastexception

ClassCastException occurs when calling another fragment's method


**Re-attached the relevant code


When I run the email app in FragmentB, the activity's 'onStop' is called.
At this time, FragmentA's method in 'onStop' does not work.

※ FragmentA and FragmentB have the same parent Activity
※ No error occurs when the app is terminated in FragmentB.

MainActivity.java

   public class MainActivity extends FragmentActivity {
    
    public Fragment fragmentA, fragmentB;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (findViewById(R.id.fragment_container) != null) {
            if (savedInstanceState != null) {
                return;
            }
            fragmentA = new FragmentA();
            fragmentB = new FragmentB();
           
            fragmentA.setArguments(getIntent().getExtras());
           
            getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, fragmentA).commit();
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
      
        ((FragmentA) getSupportFragmentManager().findFragmentById(R.id.fragment_container)).saveData();

    }

}

FragmentA.java

    View view;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    view = inflater.inflate(R.layout.fragment_timer, container, false);
    if(isLoadData){ loadData(); }
    return view;
}

public void saveData() {
    SharedPreferences timerSharedPref = getActivity().getSharedPreferences("timer", Context.MODE_PRIVATE);
    
    //...
    
    SharedPreferences.Editor editor = timerSharedPref.edit();
    String json = jsonArray.toString();
    editor.putString("jsonString", json);
    editor.apply();
}

FragmentB.java

public class FragmentB extends Fragment implements View.OnClickListener {

View view;
CardView cvContactUs;
MainActivity activity;

@Override
public void onAttach(@NonNull Context context) {
    super.onAttach(context);
    activity = (MainActivity) getActivity();
}
@Override
public void onDetach() {
    super.onDetach();
    activity = null;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    view = inflater.inflate(R.layout.fragment_b, container, false);
    cvContactUs = view.findViewById(R.id.cv_contact_us);
    return view;
}
@Override
public void onStart() {
    super.onStart();
    cvContactUs.setOnClickListener(this);
}
@Override
public void onClick(View v) {
    int id = v.getId();
    if (id == R.id.cv_contact_us) {
        sendEmail(getActivity(), "Ask a question", new String[]{"[email protected]"});
    }
}
public static void sendEmail(Context context, String title, String[] receivers){
    Intent email = new Intent(Intent.ACTION_SEND);
    email.putExtra(Intent.EXTRA_SUBJECT, title);
    email.putExtra(Intent.EXTRA_EMAIL, receivers);
    email.setType("message/rfc822");
    context.startActivity(email);
}

}


Solution

  • You have two Fragments in the stack and a single ID and the findFragmentByID() method returns the last fragment added to the container. very well when the application ends with the FragmentA I believe that you don't have any error because in the onStop() method you are casting with the FragmentA, but if you end with the FragmentB in this case you are casting the FragmentB by the FragmentA which throws the ClassCastException exception. so I suggest you use the findFragmentByTag() method here is an example

    When you add fragments:

       protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            /*
             * rest of your code
             */
            // when you add the Fragment A
            getSupportFragmentManager()
                    .beginTransaction()
                    .add(R.id.fragment_container, new FragmentA(), "A")
                    .commit();
            // when you add the Fragment A
            getSupportFragmentManager()
                    .beginTransaction()
                    .add(R.id.fragment_container, new FragmentB(), "B")
                    .commit();
        }
    

    and when you call the onStop() methode:

     @Override
        protected void onStop() {
            super.onStop();
            // ((FragmentA) getSupportFragmentManager().findFragmentByTag("A")).save();
            // ((FragmentB) getSupportFragmentManager().findFragmentByTag("B")).save();
            Fragment f = getSupportFragmentManager().findFragmentByTag("A");
            // you check if the fragment is add 
            if (f != null)
                ((FragmentA) f).save();
        }