2013-02-01 11 views
5

My DialogFragment genera ClassCastException se chiamato da Fragment, mentre funziona normalmente se chiamato da un'attività. Ho già esaminato poche altre domande con problemi simili e sostanzialmente quelle relative alle importazioni, ma non sono stato in grado di risolverlo nella mia implementazione. Ecco la mia implementazione per DialogFragment.DialogFragment genera ClassCastException se chiamato da Frammento

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

Ecco il mio Frammento che utilizza il DialogFragment sopra:

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

Questo è il log degli errori:

02-01 13: 11: 32.750: E/AndroidRuntime (15061): FATAL EXCEPTION: main 02-01 13: 11: 32.750: E/AndroidRuntime (15061): java.lang.ClassCastException: [email protected] deve implementare NoticeDialogListener 02-01 13:11: 32.750: E/An droidRuntime (15061): su com.xxx.yyy.ui.compontent.dialog.HotspotScanDialog.onAttach (HotspotScanDialog.java:122) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): su android.app. FragmentManagerImpl.moveToState (FragmentManager.java:787) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): su android.app.FragmentManagerImpl.moveToState (FragmentManager.java:1035) 02-01 13:11: 32.750: E/AndroidRuntime (15061): su android.app.BackStackRecord.run (BackStackRecord.java:635) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): su android.app.FragmentManagerImpl.execPendingActions (FragmentManager.java:1397) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): su android.app.FragmentManagerImpl $ 1.run (FragmentManager.java:426) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): su android.os.Handler.handleCallback (Handler.java:615) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): su android.os.Handler.dispatchMessage (Handler.java:92) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): in android.os.Looper.loop (Looper.java:137) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): su android.app.ActivityThread.main (ActivityThread.java:4898) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): su java.lang.reflect.Method.invokeNative (metodo nativo) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): su java.lang.reflect .Method.invoke (Method.java:511) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): a com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:1006) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): a com.android.internal.os.ZygoteInit.main (ZygoteInit.java:773) 02-01 13: 11: 32.750: E/Android Runtime (15061): at dalvik.system.NativeStart.main (Native Method)

Mi chiedo se qualcuno può dare un suggerimento su questo problema.

risposta

10

Da docs:

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

Nel codice

mListener = (SetupHotspotDialogListener) activity; 

linea tiri ClassCastException perché la vostra attività non implementa l'interfaccia SetupHotspotDialogListener. (Fragment è direttamente collegato all'attività che lo contiene, nonché a DialogFragment perché DialogFragment estende Fragment).

Sempre da 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.

Quindi, se si desidera creare FragmentDialog da Fragment suggerisco di organizzare tramite callback all'attività:

  1. creare un'interfaccia di richiamata nella vostra SmartModeFragment classe (come fai con dialogFragment) con un metodo come createDialogRequest().
  2. lasciate che la vostra attività di implementare tale interfaccia
  3. poi, quando è necessario creare dialogo, inviare richiamata Fragment-Activity
  4. luogo "di dialogo spettacolo logiche" in Activity

E 'sembrare frammento chiedere l'attività per creare una finestra di dialogo, l'attività mostra la finestra di dialogo.

MODIFICATO: Penso di aver trovato una migliore implementazione di ciò che ti serve. Ho scritto un semplice esempio di creazione di fragment dialog dal frammento con la ricezione degli eventi di callback fragment dialog in frammento.

attività:

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

Frammento:

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

ho usato il supporto 4 frammenti di libreria (android.support.v4.app.Fragment, android.support.v4.app.DialogFragment, android.support.v4.app.FragmentActivity).

e layout:

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'idea è di inviare un riferimento all'interfaccia che catturerà gli eventi di callback.

+0

Se si analizza correttamente il mio codice, si dice chiaramente "SmartMode di classe pubblica estende Fragment implementa SetupHotspotDialogListener". Questo codice funziona perfettamente con l'attività e anche l'interfaccia di callback è implementata. Vuoi dire che devo implementare l'interfaccia l'attività principale che ospita questi frammenti? – Milan

+0

Non era esattamente quello che pensavo, ma implementare quell'interfaccia nell'attività che ospitava quei frammenti ha risolto il mio problema. Anche se questo può essere limitato se si sta cercando di ottenere l'elenco delle finestre di dialogo nel frammento effettivo che ha chiamato quella finestra di dialogo. Comunque grazie per il suggerimento. – Milan

+1

Ho modificato la mia risposta.Penso che la prima parte della mia risposta non sia la soluzione migliore. –

Problemi correlati