2013-02-01 7 views
5

Mon DialogFragment lance ClassCastException s'il est appelé depuis Fragment, alors qu'il fonctionne normalement s'il est appelé à partir d'une activité. J'ai déjà examiné quelques autres questions avec des problèmes similaires et essentiellement ceux qui sont liés aux importations, mais je n'ai pas été en mesure de le résoudre dans ma mise en œuvre. Voici ma mise en œuvre pour DialogFragment.DialogFragment lève ClassCastException si appelé à partir du 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"); 
     } 
    } 
} 

Voici mon Fragment qui utilise le DialogFragment ci-dessus:

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

Ceci est le journal des erreurs:

02-01 13: 11: 32,750: E/AndroidRuntime (15061): FATAL EXCEPTION: principal 02-01 13: 11: 32.750: E/AndroidRuntime (15061): java.lang.ClassCastException: [email protected] doit implémenter NoticeDialogListener 02-01 13:11: 32.750: E/An droidRuntime (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): à l'adresse 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): à l'adresse android.app.FragmentManagerImpl $ 1.run (FragmentManager.java:426) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): at android.os.Handler.handleCallback (Handler.java:615) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): à l'adresse android.os.Handler.dispatchMessage (Handler.java:92) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): at android.os.Looper.loop (Looper.java:137) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): à l'adresse android.app.ActivityThread.main (ActivityThread.java:4898) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): à java.lang.reflect.Method.invokeNative (Méthode native) 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): à l'adresse com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:1006) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): sur com.android.internal.os.ZygoteInit.main (ZygoteInit.java:773) 02-01 13: 11: 32.750: E/Android Runtime (15061): at dalvik.system.NativeStart.main (méthode native)

Je me demande si quelqu'un peut donner un indice sur ce problème.

Répondre

10

De docs:

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

Dans votre code

mListener = (SetupHotspotDialogListener) activity; 
ligne

lancers francs ClassCastException parce que votre activité ne met pas en œuvre l'interface SetupHotspotDialogListener. (Fragment est directement lié à l'activité qui le contient, ainsi que DialogFragment car DialogFragment s'étend Fragment).

Encore une fois de 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.

Donc, si vous voulez créer FragmentDialog de Fragment Je suggère de l'organiser par callbacks à l'activité:

  1. créer une interface de rappel dans votre classe SmartModeFragment (comme vous le faites dans dialogFragment) avec une méthode comme createDialogRequest().
  2. laissez votre activité mettre en œuvre cette interface
  3. puis, lorsque vous avez besoin de créer de dialogue, envoyer le rappel Fragment-Activity
  4. lieu « logique de dialogue show » dans Activity

Il est ressembler à fragment activité demander pour créer un dialogue, l'activité affiche un dialogue.

EDITED: Je pense que j'avais trouvé une meilleure implémentation de ce dont vous avez besoin. J'ai écrit un exemple simple de création fragment dialog du fragment avec la réception des événements de rappel fragment dialog en fragment.

Activité:

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

je support 4 fragments de bibliothèque (android.support.v4.app.Fragment, android.support.v4.app.DialogFragment, android.support.v4.app.FragmentActivity).

et mises en page:

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> 

L'idée est d'envoyer une référence à l'interface qui va attraper les événements de rappel.

+0

Si vous jetez un coup d'oeil à mon code, il est clair que "public class SmartMode extends Fragment implémente SetupHotspotDialogListener". Ce code fonctionne parfaitement avec l'activité et l'interface de rappel est également implémentée. Voulez-vous dire que je dois mettre en œuvre l'interface de l'activité principale qui héberge ces fragments? – Milan

+0

Était pas exactement ce que je pensais, mais l'implémentation de ces interfaces dans l'activité qui a hébergé ces fragments a résolu mon problème. Bien que cela puisse être limité si vous essayez d'obtenir la liste de dialogue dans le fragment réel qui a appelé cette boîte de dialogue. Quoi qu'il en soit, merci pour l'indice. – Milan

+1

J'ai modifié ma réponse.Je pense que la première partie de ma réponse n'est pas la meilleure solution. –

Questions connexes