2013-02-01 29 views
5

DialogFragment của tôi ném ClassCastException nếu được gọi từ Fragment, trong khi nó hoạt động bình thường nếu được gọi từ một Activity. Tôi đã xem xét một vài câu hỏi khác với vấn đề tương tự và về cơ bản những câu hỏi đó có liên quan đến hàng nhập khẩu, nhưng tôi đã không thể giải quyết nó trong quá trình thực hiện của mình. Đây là thực hiện của tôi cho DialogFragment.DialogFragment ném ClassCastException nếu được gọi từ Fragment

 
import android.app.AlertDialog; 
import android.app.Dialog; 
import android.app.DialogFragment; 

public class HotspotScanDialog extends DialogFragment { 

    SetupHotspotDialogListener mListener; 

    @Override 
    public Dialog onCreateDialog(Bundle savedInstanceState) { 
     ... 

     .setAdapter(hotspotAdapter, new DialogInterface.OnClickListener() { 
      @Override 
      public void onClick(DialogInterface dialog, int which) { 
       mListener.onHotspotSelectedListener(hotspotAdapter.getItem(
         which).toString()); 
      } 
     })... 
    } 

    public interface SetupHotspotDialogListener { 
     public void onHotspotSelectedListener(String selection); 

    } 

    @Override 
    public void onAttach(Activity activity) { 
     super.onAttach(activity); 

     try { 
      mListener = (SetupHotspotDialogListener) activity; 
     } catch (ClassCastException ignore) { 
      // Just to make sure if anyone will be pointing at my throwing 
      // ClassCastException myself I have tried without this code as well. 
      throw new ClassCastException(activity.toString() 
        + " must implement NoticeDialogListener"); 
     } 
    } 
} 

Đây là Fragment của tôi đó là sử dụng các DialogFragment trên:

 
import android.app.AlertDialog; 
import android.app.DialogFragment; 
import android.support.v4.app.Fragment; 
import com.xxx.yyy.ui.compontent.dialog.HotspotScanDialog; 
import com.xxx.yyy.ui.compontent.dialog.HotspotScanDialog.SetupHotspotDialogListener; 

public class SmartMode extends Fragment implements SetupHotspotDialogListener { 

    private void showWifiSelectionDialog() { 
     DialogFragment setupWifiSelectionDialog = new HotspotScanDialog(); 

     /* 
     * using getFragmentManager() only says "The method 
     * show(FragmentManager, String) in the type DialogFragment is not 
     * applicable for the arguments (FragmentManager, String)" 
     */ 

     setupWifiSelectionDialog.show(getActivity().getFragmentManager(), 
       Keys.TAG.toString()); 
    } 

    @Override 
    public void onHotspotSelectedListener(String selection) { 
     // Log.d(TAG,selection); 
    } 
} 

Đây là bản ghi lỗi:

02-01 13: 11: 32,750: E/AndroidRuntime (15061): CHỨC NĂNG CHẤT LƯỢNG: chính 02-01 13: 11: 32.750: E/AndroidRuntime (15061): java.lang.ClassCastException: [email protected] phải triển khai NoticeDialogListener 02-01 13:11: 32,750: E/An droidRuntime (15061): tại com.xxx.yyy.ui.compontent.dialog.HotspotScanDialog.onAttach (HotspotScanDialog.java:122) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): tại android.app. FragmentManagerImpl.moveToState (FragmentManager.java:787) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): tại android.app.FragmentManagerImpl.moveToState (FragmentManager.java:1035) 02-01 13:11: 32.750: E/AndroidRuntime (15061): tại android.app.BackStackRecord.run (BackStackRecord.java:635) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): tại android.app.FragmentManagerImpl.execPendingActions (FragmentManager.java:1397) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): tại android.app.FragmentManagerImpl $ 1.run (FragmentManager.java:426) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): tại android.os.Handler.handleCallback (Handler.java:615) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): tại android.os.Handler.dispatchMessage (Handler.java:92) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): tại android.os.Looper.loop (Looper.java:137) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): tại android.app.ActivityThread.main (ActivityThread.java:4898) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): tại java.lang.reflect.Method.invokeNative (Phương thức Gốc) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): tại java.lang.reflect .Method.invoke (Method.java WEBC11) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): tại com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:1006) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): tại com.android.internal.os.ZygoteInit.main (ZygoteInit.java:773) 02-01 13: 11: 32.750: E/Android Thời gian chạy (15061): tại dalvik.system.NativeStart.main (Phương thức Gốc)

Tôi tự hỏi liệu có ai có thể đưa ra gợi ý về vấn đề này không.

Trả lời

10

Từ docs:

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

Trong mã của bạn

mListener = (SetupHotspotDialogListener) activity; 

dòng ném ClassCastException vì hoạt động của bạn không thực hiện giao diện SetupHotspotDialogListener. (Fragment được gắn trực tiếp với hoạt động có chứa nó, cũng như DialogFragmentDialogFragment mở rộng Fragment).

Again từ 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.

Vì vậy, nếu bạn muốn tạo FragmentDialog từ Fragment Tôi đề nghị để tổ chức nó qua callbacks để hoạt động:

  1. tạo giao diện gọi lại vào SmartModeFragment lớp học của bạn (giống như bạn thực hiện trong dialogFragment) với một phương thức như createDialogRequest().
  2. phép hoạt động của bạn thực hiện giao diện
  3. mà sau đó, khi bạn cần để tạo ra hộp thoại, gửi callback Fragment-Activity
  4. nơi "logic thoại hiển thị" vào Activity

Nó trông giống như mảnh hỏi hoạt động để tạo hộp thoại, hoạt động hiển thị hộp thoại.

CHỈNH SỬA: Tôi nghĩ rằng tôi đã tìm thấy việc triển khai tốt hơn những gì bạn cần. Tôi đã viết một ví dụ đơn giản về việc tạo ra fragment dialog từ đoạn có nhận các sự kiện gọi lại fragment dialog thành đoạn.

Hoạt động:

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

Tôi đã từng hỗ trợ 4 mảnh thư viện (android.support.v4.app.Fragment, android.support.v4.app.DialogFragment, android.support.v4.app.FragmentActivity).

Và bố trí:

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> 

Ý tưởng là gửi tham chiếu đến giao diện sẽ bắt sự kiện gọi lại.

+0

Nếu bạn xem xét kỹ mã của tôi, nó nói rõ ràng "Lớp công khai SmartMode mở rộng các cài đặt Fragment SetupHotspotDialogListener". Mã này hoạt động hoàn hảo với hoạt động và giao diện gọi lại cũng được thực hiện. Bạn có nghĩa là tôi phải thực hiện giao diện các hoạt động chính mà lưu trữ các mảnh vỡ? – Milan

+0

Không phải là excatly những gì tôi nghĩ nhưng, thực hiện những giao diện trong hoạt động lưu trữ những mảnh vỡ giải quyết vấn đề của tôi. Mặc dù điều này có thể được giới hạn nếu bạn đang cố gắng để có được danh sách hộp thoại vào mảnh thực tế được gọi là hộp thoại đó. Anyways cảm ơn cho gợi ý. – Milan

+1

Tôi đã chỉnh sửa câu trả lời của mình.Tôi nghĩ rằng phần đầu tiên của câu trả lời của tôi không phải là giải pháp tốt nhất. –

Các vấn đề liên quan