2013-02-01 16 views
5

My DialogFragment zgłasza ClassCastException, jeśli wywoływana jest z fragmentu, podczas gdy działa normalnie, jeśli wywoływana jest z działania. Rozważałem już kilka innych pytań o podobnym problemie i zasadniczo są one związane z importem, ale nie byłem w stanie go rozwiązać w mojej implementacji. Oto moja implementacja dla DialogFragment.Funkcja DialogFragment zgłasza wyjątek ClassCastException, jeśli wywoływana jest z fragmentu

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

Oto moja Fragment, który jest przy użyciu powyższej DialogFragment:

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

To jest dziennik błędów:

02-01 13: 11: 32,750: E/Android Runtime (15061): WYJĄTKOWA WYSTAWA: główna 02-01 13: 11: 32.750: E/AndroidRuntime (15061): java.lang.ClassCastException: [email protected] musi wdrożyć NoticeDialogListener 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): at android.app. FragmentManagerImpl.moveToState (FragmentManager.java:787) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): na Android.app.FragmentManagerImpl.moveToState (FragmentManager.java:1035) 02-01 13:11: 32.750: E/AndroidRuntime (15061): at android.app.BackStackRecord.run (BackStackRecord.java:635) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): w android.app.FragmentManagerImpl.execPendingActions (FragmentManager.java:1397) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): na 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): na android.os.Handler.dispatchMessage (Handler.java:92) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): o android.os.Looper.loop (Looper.java:137) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): at android.app.ActivityThread.main (ActivityThread.java:4898) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): w java.lang.reflect.Method.invokeNative (metoda macierzysta) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): at java.lang.reflect .Method.invoke (Method.java:511) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): na com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:1006) 02-01 13: 11: 32.750: E/AndroidRuntime (15061): na com.android.internal.os.ZygoteInit.main (ZygoteInit.java:773) 02-01 13: 11: 32.750: E/Android Środowisko wykonawcze (15061): w dalvik.system.NativeStart.main (metoda macierzysta)

Zastanawiam się, czy ktoś może dać wskazówkę na temat tego problemu.

Odpowiedz

10

Od docs:

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

W kodzie

mListener = (SetupHotspotDialogListener) activity; 

linia rzutów ClassCastException ponieważ Twoja aktywność nie wdrażają SetupHotspotDialogListener interfejs. (Fragment jest bezpośrednio związany z aktywnością, która go zawiera, a także DialogFragment, ponieważ DialogFragment rozszerza się o).

ponownie od 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.

Więc jeśli chcesz stworzyć FragmentDialog z Fragment Proponuję zorganizować go za pośrednictwem wywołania zwrotne do aktywności:

  1. stworzyć interfejs wywołania zwrotnego do swojego SmartModeFragment klasy (podobnie jak w oknie dialogowymFragment) za pomocą jednej metody, takiej jak createDialogRequest().
  2. niech Twoja aktywność wdrożenia tego interfejsu
  3. wtedy, gdy trzeba utworzyć okno, wyślij zwrotnego od Fragment do Activity
  4. miejscu "logiki pokaz Dialog" w Activity

To wygląda jak fragment zapytać aktywność aby utworzyć dialog, okno dialogowe pokazuje aktywność.

EDYTOR: Wydaje mi się, że znalazłem lepszą implementację tego, czego potrzebujesz. Napisałem prosty przykład tworzenia fragment dialog z fragmentu z odbieraniem zdarzeń wywołania zwrotnego fragment dialog na fragment.

aktywny:

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

kiedyś podpora 4 fragmenty biblioteki (android.support.v4.app.Fragmentandroid.support.v4.app.DialogFragment, android.support.v4.app.FragmentActivity).

i układy:

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> 

Pomysł jest wysyłanie odwołania do interfejsu, który będzie przechwytywał zdarzenia wywołania zwrotnego.

+0

Jeśli przyjrzysz się dokładnie mojemu kodowi, wyraźnie powiesz "public class SmartMode rozszerza Fragment implements SetupHotspotDialogListener". Ten kod działa doskonale z działaniem i jest również implementowany interfejs wywołania zwrotnego. Czy masz na myśli, że muszę zaimplementować interfejs jako główną aktywność, która obsługuje te fragmenty? – Milan

+0

Nie było to dokładnie to, o czym myślałem, ale wdrożenie tego interfejsu w działaniu, które hostowało te fragmenty rozwiązało mój problem. Chociaż może to być ograniczone, jeśli próbujesz uzyskać listę dialogów do faktycznego fragmentu, który wywołał to okno dialogowe. W każdym razie dzięki za podpowiedź. – Milan

+1

Edytowałem swoją odpowiedź.Myślę, że pierwsza część mojej odpowiedzi nie jest najlepszym rozwiązaniem. –