2012-05-10 19 views
18

Robię trochę pracy w tle i pokazuję DialogFragment, gdy to robię. Po wykonaniu mojej pracy i wywołaniu odpowiedniego wywołania zwrotnego zamykam okno dialogowe. Kiedy robię, mam awarię spowodowaną przez NPE w android źródła, tutaj:Błąd otwierania okna dialogowego przy użyciu wyjątku NullPointerException

void dismissInternal(boolean allowStateLoss) { 
     if (mDialog != null) { 
      mDialog.dismiss(); 
      mDialog = null; 
     } 
     mRemoved = true; 
     if (mBackStackId >= 0) { 
      getFragmentManager().popBackStack(mBackStackId, 
        FragmentManager.POP_BACK_STACK_INCLUSIVE); 
      mBackStackId = -1; 
     } else { 
      FragmentTransaction ft = getFragmentManager().beginTransaction(); 
      ft.remove(this); 
      if (allowStateLoss) { 
       ft.commitAllowingStateLoss(); 
      } else { 
       ft.commit(); 
      } 
     } 
    } 

specjalnie na linii: FragmentTransaction ft = getFragmentManager().beginTransaction();

+1

Ma fragment/działanie z którego odwołujesz okno dialogowe znikające z tła, tzn. wywoływana jest jego metoda 'onPause'? W tym przypadku spodziewałbym się problemów i starałbym się obejść takie problemy, upewniając się, że nie robię takich rzeczy jak zamykanie okien dialogowych, dopóki nie zostanie wywołany 'onResume' (poprzez implementację metody paused handler notowanej [tutaj] (http://stackoverflow.com/questions/7992496/how-to-handle-asynctask-onpostexecute-when-paused-to-avoid-illegalstateexception) lub [tutaj] (http://stackoverflow.com/questions/8040280/how-to -handle-handler -messages-when-activity-fragment-is-paused) – PJL

+0

@PJL Interesujący punkt, powinienem się zalogować Pause.To ma sens, że onPause zostanie wywołany.Pokażę twojemu podejściu strzał – LuxuryMode

Odpowiedz

5

Mój zakład jest to, że kod, który pisał to z wątku tła ... nie wolno aktualizować interfejsu użytkownika z dowolnego miejsca poza wątkiem interfejsu użytkownika.

Można użyć onPostExecute() lub runOnUiThread(), aby osiągnąć swój cel (jeśli moje przypuszczenie jest słuszne, co się dzieje)

+0

Wspierając ciebie proszę pana, ja też myślę to samo ... –

+2

Zastanawiam się nad tym, jednak otrzymuję ten sam wynik, nawet jeśli wywołuję funkcję getActivity(). runOnUiThread, chociaż tak naprawdę nie próbowałem skonfigurować AsyncTask – LuxuryMode

+0

Mam ten sam problem i już dzwoniłem ' dismiss() 'z wątku UI: –

14

ten może również wystąpić, gdy dzwonisz odrzucenie() przed nazwali show() jak powiedział Sogger.

Po skonstruowaniu obiektu Dialog, ale przed wyświetleniem okna dialogowego nie można podać, jeśli (mDialog! = Null) można przekazać i wystąpi wyjątek NullPointerException.

Podczas sprawdzania czy mDialog jest null lub nie,

if (mDialog != null) { 
    mDialog.dismiss(); 
    mDialog = null; 
} 

Dodaj więcej warunków, takich jak poniżej,

if ((mDialog != null) && mDialog.isAdded() && mDialog.isResumed()) { 
    mDialog.dismiss(); 
    mDialog = null; 
} 

myślę że mDialog.isAdded() stan może być za mało ...

+0

Sprawdzanie 'isAdded()' i 'isResumed()' jest zbędne - jeśli fragment zostanie wznowiony, to również zostanie dodany. Zobacz [fragmenty dokumentacji cyklu życia] (https://developer.android.com/guide/components/fragments.html#Creating). – yuval

1

Sprawdzanie, czy jest widoczne przed dimingiem, może uniknąć wyjątku wskaźnika pustego

if (mDialog != null && mDialog.isVisible) { 
     mDialog.dismiss(); 
     mDialog = null; 
    } 
10

Najprostszym rozwiązaniem jest sprawdzenie "getFragmentManager()" dla "null" przed wywołaniem metody "dismiss()". Ponadto można przedłużyć „DialogFragment” klasa i metoda override „odrzucenie()” w celu sprawdzenia go tam:

@Override 
public void dismiss() 
{ 
    if (getFragmentManager() != null) super.dismiss(); 
} 
6

Znam ten komunikat jest stary, ale wpadłem na podobnym przypadku, że muszę do solvew bez refaktoringu lub zmiany dużo kodu. Nadzieję, że to przydatne dla kogoś

package com.example.playback; 

import android.os.Bundle; 
import android.support.v4.app.DialogFragment; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 

public class SaferDialogFragment extends DialogFragment { 

    private boolean allowStateLoss = false; 
    private boolean shouldDismiss = false; 

    public SaferDialogFragment() { 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setRetainInstance(true); 
    } 

    @Override 
    public void onStart() { 
     super.onStart(); 
     //check if we should dismiss the dialog after rotation 
     if (shouldDismiss) { 
      if (allowStateLoss) 
       dismissAllowingStateLoss(); 
      else 
       dismiss(); 
     } 
    } 

    @Override 
    public void dismiss() { 
     if (getActivity() != null) { // it's "safer" to dismiss 
      shouldDismiss = false; 
      super.dismiss(); 
     } else { 
      shouldDismiss = true; 
      allowStateLoss = false; 
     } 
    } 

    @Override 
    public void dismissAllowingStateLoss() { 
     if (getActivity() != null) { // it's "safer" to dismiss 
      shouldDismiss = false; 
      super.dismissAllowingStateLoss(); 
     } else 
      allowStateLoss = shouldDismiss = true; 
    } 

    //keeping dialog after rotation 
    @Override 
    public void onDestroyView() { 
     if (getDialog() != null && getRetainInstance()) 
      getDialog().setDismissMessage(null); 
     super.onDestroyView(); 
    } 



    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
      Bundle savedInstanceState) { 
     /** omitted code **/ 
     return super.onCreateView(inflater, container, savedInstanceState); 
    } 
} 
1

Funkcja zwrotna, która jest wywoływana jest prawdopodobnie z działalności, które są lub powinny być zniszczone (po zmianie orientacji), również okno dialogowe postępu może być tworzony z tej samej działalności. Może to spowodować NPE. Oddzwonień na działania nie należy wywoływać z zadań w tle, aby zapobiec tego rodzaju problemom. Odłącz zadanie tła od działania, na przykład za pomocą otto, lub uniemożliwi zadanie tła wywoływania (zostanie) zniszczonej aktywności.

Trochę kodu kopalni:

statycznym wewnątrz klasy aktywności:

public static class ProgressDialogFragment extends DialogFragment { 
    ProgressDialog dialog; 

    public ProgressDialogFragment() { 
    } 

    @Override 
    public Dialog onCreateDialog(Bundle savedInstanceState) { 
     dialog = new ProgressDialog(getActivity(), getTheme()); 
     dialog.setTitle(getString(R.string.please_wait)); 
     dialog.setMessage(getString(R.string.uploading_picture)); 
     dialog.setIndeterminate(true); 
     dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); 
     return dialog; 
    } 

} 

Otto subskrypcji aktywności:

@Subscribe 
public void onUploadEvent(UploadAvatarEvent uploadAvatarEvent) { 
    switch (uploadAvatarEvent.state) { 
     case UploadAvatarEvent.STATE_UPLOADING: 
      if (!mProgressDialog.isAdded()) { 
       mProgressDialog.show(getFragmentManager(), TAG_PROGRESS_DIALOG); 
      } 
      break; 
     case UploadAvatarEvent.STATE_UPLOAD_SUCCES: 
      mProgressDialog.dismiss(); 
      break; 
     case UploadAvatarEvent.STATE_UPLOAD_ERROR: 
      mProgressDialog.dismiss(); 
      break; 
    } 
} 

onCreate() aktywności:

 mProgressDialog = (ProgressDialogFragment) getFragmentManager().findFragmentByTag(TAG_PROGRESS_DIALOG); 
    if (mProgressDialog == null) { 
     mProgressDialog = new ProgressDialogFragment(); 
    } 
Powiązane problemy