Comprendere il comportamento di startActivityForResult per Fragment e Activity

L’intero startActivityForResult e onActivityResult è consentito una comunicazione a 2 vie tra l’attività di origine e l’attività di destinazione. Il suo flusso è come mostrato nello schema seguente.

Dal flusso sottostante, possiamo facilmente comprendere il flusso di OnActivityResult dall’attività di origine all’attività di destinazione

La chiamata di attività di origine, startActivityForResult inviando l’intento insieme al codice di richiesta ad Android SDK.

Android SDK apre quindi l’attività di conseguenza come indicato nell’Intento.
Una volta che l’attività di destinazione ha terminato con il suo lavoro, ritorna alla sua attività chiamante.

Potrebbe inviare il risultato usando setResult inviando il resultCode e intent

Diverse note qui:

Il resultCode viene utilizzato dall’attività di destinazione per contrassegnare alla sua attività di origine quale sia lo stato (ad esempio OK, Annulla, ecc.).

Il codice di richiesta viene utilizzato dall’attività di origine per sapere quale attività di destinazione sta restituendo la chiamata.

Potremmo vedere che l’attività di destinazione non ha visibilità del codice di richiesta.

Flusso di frammenti startActivityForResult non documentato

In Fragment, abbiamo anche la funzione startActivityForResult da chiamare e anche la funzione onActivityResult da sovrascrivere.

Ciò solleva diverse domande,ad esempio Come funziona? È uguale a startActivityForResult dell’attività e onActivityResult? Come sono correlati?
La risposta breve è, sono simili ma sottilmente diversi. Una frequente causa di confusione e bug. Quindi è importante capire la somiglianza e le differenze.

Il flusso di frammenti illustrato.

Di seguito è riportato il diagramma che illustra chiaramente come funziona tutto insieme. Le differenze con il flusso startActivityForResult di activity e onActivityResult sono colorate in ROSSO.

Cerchiamo di più elaborare su di esso.

Quando chiamiamo startActivityForResult di Fragment (nota: NOT activity?.startActivityForResult), la creazione dell’attività di destinazione è la stessa. Tuttavia, la differenza è onActivityResult.

startActivityForResult() deve gestire da fragment‘s onActivityForResult()

getActivity().startActivityForResult() deve gestire da activity” s onActivityForResult()

Se sei su un fragment e si desidera gestire il risultato sul fragment, utilizzare onActivityForResult() altrimenti, se si desidera gestire il activity del frammento, utilizzare getActivity.startActivityForResult()

Quando Android SDK restituisce onActivityResult, il codice di richiesta è stato alterato. Un 0xP0000 viene aggiunto al requestCode originale.

Il valore P inizia da 1 e incrementato per ogni onActivityResult viene chiamato dallo stesso frammento di destinazione. (Se viene chiamato un altro frammento di destinazione, il valore P viene ripristinato).

ad esempio se il requestCode originale è 0xFF (cioè 255), il requestCode restituito la prima volta sarà 0x100FF. La seconda volta requestCode di ritorno sarà 0x200FF.

Al ritorno a onActivityResult dell’attività di origine, si prevede che debba chiamare super.onActivityResult, che risiede in FragmentActivity (il genitore di AppCompatActivity)

onActivityResult in FragmentActivity estrarrà quindi il valore P (utilizzando requestCode >> 16). Il P è l’indice della matrice in cui è memorizzato il frammento di origine. (ad esempio se requestCode è 0x200FF, quindi 0x200FF >> 16 = 2)

Utilizzando il valore P, ora ha accesso al frammento di origine, che viene utilizzato nel passaggio 9 di seguito.

Ora, elimina il valore P dal requestCode (usando requestCode & 0xffff), per tornare al codice di richiesta originale (ad esempio se requestCode è 0x200FF, quindi 0x200FF & 0xffff = 0xFF)

Poiché ora ottiene il codice di richiesta originale creato dal frammento di origine, potrebbe chiamare onActivityResult del frammento di origine con il codice di richiesta originale.

Alcuni punti fondamentali che vogliono sapere.

A. Il comportamento di startActivityForResult di Activity è diverso da startActivityForResult di Fragment

In Fragment, se chiamiamo activity?.startActivityForResult(...), Allora Fragment onActivityResult non verrà chiamato automaticamente.

B. Se sovrascriviamo onActivityResult di activity, assicurati di avere super.onActivityResult sul posto

Se sovrascriviamo l’attività di origine onActivityResult, ma dimentichiamo di avere super.onActivityResult, allora il frammento onActivityResult non verrà chiamato.

C. Il requestCode visto in onActivityResult di activity è diverso da un frammento fornito

A causa del motivo, Android SDK ha aggiunto P a requestCode, in activity onActivityResult, non otterremo mai l’identico requestCode lì. Questo a volte causa confusione allo sviluppatore durante il debug del codice lì.

D. Quando un’attività viene ripristinata dallo stato (ad esempio onStateInstance != null, deve evitare di ricreare il suo frammento.

Quando viene chiamato onActivityResult, ha cercato di recuperare il frammento originale. Questo viene eseguito anche per l’attività che viene ripristinata da uno stato ucciso (ad esempio emulato usando Don’t Keep Activity).

Quindi se lo sviluppatore ricrea il frammento ogni volta che viene chiamato onCreate (indipendentemente dal fatto che si tratti di uno stato ripristinato o meno), il Frammento originale che è stato ripristinato verrà distrutto e onActivityResult del chiamante, il frammento misteriosamente non verrà chiamato.

Questa è una trappola anche per molti sviluppatori esperti e app rilasciate sul campo, in quanto è molto difficile un bug identificato (dal momento che non sta accadendo ogni volta, e richiedono un flusso più complesso per innescare).

Grazie per aver letto…