DialogFragment throws ClassCastException if called from Fragment

前端 未结 1 1648
执念已碎
执念已碎 2020-12-16 05:15

My DialogFragment throws ClassCastException if called from Fragment, while it is working normally if called from an Activity. I have already looked at few other que

相关标签:
1条回答
  • 2020-12-16 06:04

    From docs:

     onAttach(Activity) called once the fragment is associated with its activity.
    

    In your code

     mListener = (SetupHotspotDialogListener) activity;
    

    line throws ClassCastException because your activity don't implement SetupHotspotDialogListener interface. (Fragment is directly tied to the activity that contains it, as well as DialogFragment because DialogFragment extends Fragment).

    Again from docs

    In some cases, you might need a fragment to share events with the activity. A good way to do that is to define a callback interface inside the fragment and require that the host activity implement it. When the activity receives a callback through the interface, it can share the information with other fragments in the layout as necessary.

    So if you want to create FragmentDialog from Fragment I suggest to organize it via callbacks to activity:

    1. create callback interface into your SmartMode Fragment class (like you do into dialogFragment) with one method like createDialogRequest().
    2. let your activity implement that interface
    3. then, when you need to create dialog, send callback from Fragment to Activity
    4. place "show dialog logics" into Activity

    It's look like fragment ask activity to create dialog, activity shows dialog.

    EDITED: I think i had found better implementation of what you need. I've write a simple example of creating fragment dialog from fragment with receiving fragment dialog callback events into fragment.

    Activity:

    public class MyFragmentActivity extends FragmentActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_my_fragment);
    
            // first start of activity
            if (savedInstanceState == null) {
                // put fragment to activity layout 
                MyFragment fragment = new MyFragment();
                FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
                ft.replace(R.id.fragmentContainer, fragment, "fragment");
                ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
                ft.commit();
            }
        }
    
    }
    

    Fragment:

    public class MyFragment extends Fragment implements MyDialogInterface {
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            super.onCreateView(inflater, container, savedInstanceState);
    
            View fragmentView = inflater.inflate(R.layout.fragment, null);
    
            // button which shows dialog
            Button showDialogButton = (Button) fragmentView.findViewById(R.id.showDialog);
            showDialogButton.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    // create fragment dialog.
                    FragmentDialog dialog = FragmentDialog.getInstance(MyFragment.this);
                    dialog.show(getActivity().getSupportFragmentManager(), "dialog");
                }
            });
    
            return fragmentView;
        }
    
        @Override
        public void onClickEvent() {
            // receive click events from dialog fragment
            Log.e(getClass().getSimpleName(), "onClickEvent");
        }
    
    }
    

    FragmentDialog:

    public class FragmentDialog extends DialogFragment {
    
        public interface MyDialogInterface extends Serializable {
            public void onClickEvent();
        }
    
        private MyDialogInterface callbackListener;
    
        /**
         * dialogInterface - instance of MyDialogInterface which will handle
         * callback events
         */
        public static FragmentDialog getInstance(MyDialogInterface dialogInterface) {
            FragmentDialog fragmentDialog = new FragmentDialog();
    
            // set fragment arguments
            Bundle args = new Bundle();
            args.putSerializable("dialogInterface", dialogInterface);
            fragmentDialog.setArguments(args);
    
            return fragmentDialog;
        }
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setStyle(STYLE_NO_TITLE, 0);
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    
            View pushDialogView = getActivity().getLayoutInflater().inflate(R.layout.fragment_dialog, null);
    
            // get reference to MyDialogInterface instance from arguments
            callbackListener = (MyDialogInterface) getArguments().getSerializable("dialogInterface");
    
            Button cancelButton = (Button) pushDialogView.findViewById(R.id.button);
            cancelButton.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    // send click event
                    callbackListener.onClickEvent();
                }
            });
    
            return pushDialogView;
        }
    
    }
    

    I used support 4 library fragments

    android.support.v4.app.Fragment
    android.support.v4.app.DialogFragment
    android.support.v4.app.FragmentActivity
    

    And layouts:

    activity_my_fragment.xml :

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
       android:id="@+id/fragmentContainer"
       android:layout_width="match_parent"
       android:layout_height="match_parent" />
    

    fragment.xml :

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:background="#a00"
       android:orientation="vertical" >
    
       <Button
         android:id="@+id/showDialog"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="show doalog" />
    </LinearLayout>
    

    fragment_dialog.xml :

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:background="#fe3"
       android:orientation="vertical" >
    
       <Button
          android:id="@+id/button"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="click me" />
     </LinearLayout>
    

    The idea is to send reference to interface which will catch callback events.

    0 讨论(0)
提交回复
热议问题