2013-02-01 5 views
5

aufgerufen wird. My DialogFragment löst ClassCastException aus, wenn sie von Fragment aufgerufen wird, während sie normal funktioniert, wenn sie von einer Aktivität aufgerufen wird. Ich habe mir bereits einige andere Fragen mit ähnlichen Problemen angeschaut, die im Wesentlichen mit Importen zu tun haben, aber ich konnte sie in meiner Implementierung nicht lösen. Hier ist meine Implementierung für DialogFragment.DialogFragment löst ClassCastException aus, wenn sie von 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"); 
     } 
    } 
} 

Hier ist mein Fragment, das die oben DialogFragment verwendet:

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

Dies ist das Fehlerprotokoll:

02-01 13: 11: 32.750: E/Android Runtime (15061): FATALE AUSNAHME: Haupt 02-01 13: 11: 32.750: E/AndroidRuntime (15061): java.lang.ClassCastException: [email protected] muss NoticeDialogListener implementieren 02-01 13:11: 32.750: E/An droidRuntime (15061): at com.xxx.yyy.ui.compontent.dialog.HotspotScanDialog.onAttach (HotspotScanDialog.java:122) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): bei android.app. FragmentManagerImpl.moveToState (FragmentManager.java:787) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): bei android.app.FragmentManagerImpl.moveToState (FragmentManager.java:1035) 02-01 13:11: 32.750: E/AndroidRuntime (15061): bei android.app.BackStackRecord.run (BackStackRecord.java:635) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): bei android.app.FragmentManagerImpl.execPendingActions (FragmentManager.java:1397) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): bei android.app.FragmentManagerImpl $ 1.run (FragmentManager.java:426) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): bei android.os.Handler.handleCallback (Handler.java:615) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): bei android.os.Handler.dispatchMessage (Handler.java:92) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): um android.os.Looper.loop (Looper.java:137) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): bei android.app.ActivityThread.main (ActivityThread.java:4898) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): um java.lang.reflect.Method.invokeNative (native Methode) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): at java.lang.reflect .Method.invoke (Methode.java:511) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): um com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java: 1006) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): unter com.android.internal.os.ZygoteInit.main (ZygoteInit.java:773) 02-01 13: 11: 32.750: E/Android Laufzeit (15061): at dalvik.system.NativeStart.main (Native Methode)

Ich frage mich, ob jemand einen Hinweis auf dieses Problem geben kann.

Antwort

10

Von docs:

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

In Ihrem Code

mListener = (SetupHotspotDialogListener) activity; 

Linie wirft ClassCastException weil Ihre Aktivität SetupHotspotDialogListener Schnittstelle nicht implementieren. (Fragment ist direkt an die Aktivität gebunden, die es enthält, sowie DialogFragment, weil DialogFragment erweitert Fragment).

wieder von 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.

Also, wenn Sie FragmentDialog von Fragment erstellen möchten schlage ich vor, es über Rückrufe an Aktivität zu organisieren:

  1. erstellen Callback-Schnittstelle in Ihre SmartModeFragment Klasse (wie in dialogFragment) mit einer Methode wie createDialogRequest().
  2. lassen Sie Ihre Aktivität
  3. dann diese Schnittstelle implementieren, wenn Sie Dialog erstellen müssen, fragen Es ist aussehen Fragment Rückruf Fragment-Activity
  4. Ort „show Dialog Logiken“ in Activity

senden Aktivität um den Dialog zu erstellen, zeigt die Aktivität den Dialog an.

EDITED: Ich denke, ich hatte bessere Umsetzung von was Sie brauchen gefunden. Ich habe ein einfaches Beispiel für die Erstellung von fragment dialog aus Fragment mit dem Empfang von fragment dialog Callback-Ereignissen in Fragment geschrieben.

Aktivität:

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 Träger 4 Bibliotheksfragmente verwendet (android.support.v4.app.Fragment, android.support.v4.app.DialogFragment, android.support.v4.app.FragmentActivity).

und 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> 

Die Idee ist der Verweis auf die Schnittstelle, die Callback-Ereignisse abfängt.

+0

Wenn Sie sich meinen Code genau anschauen, heißt es klar "öffentliche Klasse SmartMode erweitert Fragment implementiert SetupHotspotDialogListener". Dieser Code funktioniert perfekt mit der Aktivität und es ist auch die Callback-Schnittstelle implementiert. Meinst du, dass ich die Schnittstelle die Hauptaktivität implementieren muss, die diese Fragmente hostet? – Milan

+0

War nicht genau das, was ich dachte, aber das Implementieren dieser Schnittstelle in der Aktivität, die diese Fragmente beherbergte, löste mein Problem. Dies kann jedoch eingeschränkt werden, wenn Sie versuchen, eine Dialogliste in das eigentliche Fragment zu bringen, das dieses Dialogfeld aufgerufen hat. Wie auch immer, danke für den Hinweis. – Milan

+1

Ich habe meine Antwort bearbeitet.Ich denke, der erste Teil meiner Antwort ist nicht die beste Lösung. –