【问题标题】:DialogFragment throws ClassCastException if called from Fragment如果从 Fragment 调用 DialogFragment 将引发 ClassCastException
【发布时间】:2013-01-16 10:00:33
【问题描述】:

如果从 Fragment 调用,我的 DialogFragment 会抛出 ClassCastException,而如果从 Activity 调用,它会正常工作。我已经查看了其他几个具有类似问题的问题,基本上这些问题与导入有关,但我无法在我的实现中解决它。这是我对 DialogFragment 的实现。

导入 android.app.AlertDialog; 导入android.app.Dialog; 导入android.app.DialogFragment; 公共类 HotspotScanDialog 扩展 DialogFragment { SetupHotspotDialogListener mListener; @覆盖 公共对话 onCreateDialog(Bundle savedInstanceState) { ... .setAdapter(hotspotAdapter, new DialogInterface.OnClickListener() { @覆盖 public void onClick(DialogInterface dialog, int which) { mListener.onHotspotSelectedListener(hotspotAdapter.getItem( 其中).toString()); } })... } 公共接口 SetupHotspotDialogListener { 公共无效 onHotspotSelectedListener(字符串选择); } @覆盖 公共无效 onAttach(活动活动){ super.onAttach(活动); 尝试 { mListener = (SetupHotspotDialogListener) 活动; } 捕捉(ClassCastException 忽略){ // 只是为了确定是否有人会指着我的投掷 // ClassCastException 我自己也试过没有这个代码。 抛出新的 ClassCastException(activity.toString() + "必须实现NoticeDialogListener"); } } }

这是我使用上述 DialogFragment 的片段:

导入 android.app.AlertDialog; 导入android.app.DialogFragment; 导入android.support.v4.app.Fragment; 导入 com.xxx.yyy.ui.compontent.dialog.HotspotScanDialog; 导入 com.xxx.yyy.ui.compontent.dialog.HotspotScanDialog.SetupHotspotDialogListener; 公共类 SmartMode 扩展片段实现 SetupHotspotDialogListener { 私人无效showWifiSelectionDialog(){ DialogFragment setupWifiSelectionDialog = new HotspotScanDialog(); /* * 使用 getFragmentManager() 只会说“方法 * DialogFragment 类型中的 show(FragmentManager, String) 不是 * 适用于参数 (FragmentManager, String)" */ setupWifiSelectionDialog.show(getActivity().getFragmentManager(), Keys.TAG.toString()); } @覆盖 公共无效 onHotspotSelectedListener(字符串选择){ // Log.d(TAG,selection); } }

这是错误日志:

02-01 13:11:32.750:E/AndroidRuntime(15061):致命异常:主要 02-01 13:11:32.750: E/AndroidRuntime(15061): java.lang.ClassCastException: com.milanix.tuki.UiMainActivity@41d75350 必须实现 NoticeDialogListener 02-01 13:11:32.750: E/AndroidRuntime(15061): 在 com.xxx.yyy.ui.compontent.dialog.HotspotScanDialog.onAttach(HotspotScanDialog.java:122) 02-01 13:11:32.750: E/AndroidRuntime(15061): 在 android.app.FragmentManagerImpl.moveToState(FragmentManager.java:787) 02-01 13:11:32.750: E/AndroidRuntime(15061): 在 android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1035) 02-01 13:11:32.750: E/AndroidRuntime(15061): 在 android.app.BackStackRecord.run(BackStackRecord.java:635) 02-01 13:11:32.750: E/AndroidRuntime(15061): 在 android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1397) 02-01 13:11:32.750: E/AndroidRuntime(15061): 在 android.app.FragmentManagerImpl$1.run(FragmentManager.java:426) 02-01 13:11:32.750: E/AndroidRuntime(15061): 在 android.os.Handler.handleCallback(Handler.java:615) 02-01 13:11:32.750: E/AndroidRuntime(15061): 在 android.os.Handler.dispatchMessage(Handler.java:92) 02-01 13:11:32.750: E/AndroidRuntime(15061): 在 android.os.Looper.loop(Looper.java:137) 02-01 13:11:32.750: E/AndroidRuntime(15061): 在 android.app.ActivityThread.main(ActivityThread.java:4898) 02-01 13:11:32.750: E/AndroidRuntime(15061): 在 java.lang.reflect.Method.invokeNative(Native Method) 02-01 13:11:32.750: E/AndroidRuntime(15061): 在 java.lang.reflect.Method.invoke(Method.java:511) 02-01 13:11:32.750: E/AndroidRuntime(15061): 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1006) 02-01 13:11:32.750: E/AndroidRuntime(15061): 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:773) 02-01 13:11:32.750: E/AndroidRuntime(15061): at dalvik.system.NativeStart.main(Native Method)

我想知道是否有人可以就这个问题提供提示。

【问题讨论】:

    标签: android fragment android-dialogfragment


    【解决方案1】:

    来自docs

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

    在你的代码中

     mListener = (SetupHotspotDialogListener) activity;
    

    line throws ClassCastException 因为你的活动没有实现SetupHotspotDialogListener 接口。 (Fragment 直接与包含它的活动相关联,DialogFragment 因为DialogFragment 扩展了Fragment)。

    再次来自docs

    在某些情况下,您可能需要一个片段来与活动共享事件。一个好的方法是在片段内定义一个回调接口并要求宿主活动实现它。当activity通过接口接收到回调时,可以根据需要与布局中的其他fragment共享信息。

    因此,如果您想从Fragment 创建FragmentDialog,我建议通过回调活动来组织它:

    1. 使用createDialogRequest() 之类的一种方法在SmartMode Fragment 类中创建回调接口(就像在dialogFragment 中所做的那样)。
    2. 让您的活动实现该接口
    3. 然后,当您需要创建对话框时,将回调从Fragment 发送到Activity
    4. 将“显示对话逻辑”放入Activity

    看起来像片段要求活动创建对话框,活动显示对话框。

    编辑: 我想我已经找到了更好的实现你需要的东西。我写了一个从片段创建fragment dialog 的简单示例,并将fragment dialog 回调事件接收到片段中。

    活动:

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

    片段:

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

    片段对话框:

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

    我使用了支持 4 个库片段

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

    和布局:

    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>
    

    这个想法是发送对将捕获回调事件的接口的引用。

    【讨论】:

    • 如果您仔细查看我的代码,它会清楚地显示“公共类 SmartMode 扩展 Fragment 实现 SetupHotspotDialogListener”。此代码与活动完美配合,并且还实现了回调接口。你的意思是我必须实现承载这些片段的主要活动的接口?
    • 并不是我想的那样,但是在托管这些片段的活动中实现这些接口解决了我的问题。虽然如果您试图将对话框列表放入调用该对话框的实际片段中,这可能会受到限制。无论如何感谢您的提示。
    • 我已经编辑了我的答案。我认为我的答案的第一部分不是最好的解决方案。
    猜你喜欢
    • 2013-10-15
    • 1970-01-01
    • 1970-01-01
    • 2014-11-11
    • 1970-01-01
    • 1970-01-01
    • 2016-10-30
    • 2022-01-21
    • 1970-01-01
    相关资源
    最近更新 更多