2011-11-27 13 views
19

Ho recentemente convertito le mie attività in frammenti.Frammenti sostituiti durante l'esecuzione di AsyncTask - NullPointerException su getActivity()

Utilizzando qualcosa di simile a Tab-Navigation i frammenti vengono sostituiti quando l'utente seleziona un'altra scheda. Dopo aver popolato il frammento, avvio almeno un AsyncTask per ottenere alcune informazioni da Internet. Tuttavia - se l'utente passa a un'altra scheda come viene eseguito il doBackground-method dalla mia AsyncTask - il frammento è sostituito e quindi sto ottenendo un NullPointerException nelle linee marcate:

@Override 
protected Object doInBackground(Object... params) { 
    ... 
    String tempjson = helper.SendPost(getResources().getText(R.string.apiid)); //ERROR: Fragment not attached 
    ... 
} 

protected onPostExecute(Object result) { 
    ... 
    getActivity().getContentResolver() //NULLPOINTEREXCEPTION 
    getView().findViewById(R.id.button) //NULL 
    ... 
} 

getActivity() e getResources() causa un errore perché il mio frammento è stato sostituito.

Le cose che ho provato:

  • Calling annullare metodo sul mio AsyncTask (non risolverà primo errore né il secondo errore se il frammento viene sostituita mentre onPostExecute() viene eseguito)
  • controllando se getActivity() è null o chiamando this.isDetached() (non una vera e propria correzione e che avevo bisogno di controllare ogni volta che io chiamo getActivity() e così via)

Quindi la mia domanda è: quale sarebbe il migliore per sbarazzarsi di questi problemi AsyncTask? Non ho avuto questi problemi utilizzando Attività in quanto non sono stati "uccisi"/distaccati sul cambiamento di tabulazione (il che ha comportato un maggiore utilizzo della memoria - il motivo per cui mi piace passare a Fragments)

risposta

18

Poiché AsyncTask è in esecuzione in background , il tuo frammento potrebbe staccarsi dalla sua attività genitore dal momento in cui finisce. Come hai scoperto, puoi utilizzare isDetached() per verificare. Non c'è niente di sbagliato in questo, e non devi controllare ogni volta, basta considerare i frammenti e i cicli di vita delle attività. altri

due alternative:

  • Usa Pale, sono progettati per giocare più bello con frammenti
  • Spostare il carico AsyncTask alle interfacce di attività genitore e di uso per disaccoppiare dai frammenti. L'attività dovrebbe sapere se un frammento è presente o meno e agire di conseguenza (eventualmente scartando il risultato se il frammento è scomparso).
+8

si dovrebbe usare isDetached() solo se hai rimosso il frammento in modo esplicito. Altrimenti, dovresti usare isAdded() per gestire i casi in cui il sistema ha distrutto il collegamento tra la tua attività e il tuo frammento. – pcans

+0

@Nikolay Elenkov in che modo il ciclo di vita può evitare di controllare ogni volta prima di chiamare getactivity? – Bear

-1

Hai provato a chiamare setRetainInstance(true); nella funzione onCreate() della classe del frammento?

+1

Questo non aiuta in questo caso, i problemi sono gli stessi. Per ora l'ho risolto creando campi per l'attività e vista e impostandoli in 'onActivityCreated()' usando 'view = getView()' e così via. – Boni2k

4

Oggi ho affrontato lo stesso problema: quando ho cambiato il fragment viene visualizzato se il AsyncTask non è ancora finito, e si tenta di accedere alla view per popolarlo con qualche elemento in più, sarebbe restituire un NullPointerException.

Ho risolto il problema sovrascrivendo un metodo del ciclo di vita dei frammenti: onDetach(). Questo metodo viene chiamato nel momento in cui lo fragment viene staccato da activity.

Quello che devi fare è chiamare il metodo cancel() sul tuo AsyncTask.Questo fermerà l'esecuzione dell'attività evitando lo NullPointerExecption.

Ecco un esempio di onDetach():

@Override 
public void onDetach() { 
    super.onDetach(); 
    task.cancel(true); 
} 

controllare questa pagina per ottenere ulteriori informazioni su frammenti del ciclo di vita: http://developer.android.com/reference/android/app/Fragment.html#Lifecycle E questo per visualizzare più su Annullamento di un compito: http://developer.android.com/reference/android/os/AsyncTask.html

+0

Grazie, grazie mille. Questo ha risolto il mio problema che mi aveva tormentato per una settimana! –

Problemi correlati