DevCorner: creiamo qualche Dialog [METEO]

Roberto Orgiu
Roberto Orgiu
DevCorner: creiamo qualche Dialog [METEO]

La scorsa puntata abbiamo visto come ritrovare la posizione dell’utilizzatore ma, per fornire una migliore esperienza utente, dobbiamo anche notificare che abbiamo questo dato e chiedere conferma all’utente della veridicità della nostra affermazione. Come possiamo fare se non utilizzando un bel popup?

LEGGI ANCHE: Sviluppiamo un’app per la lettura dei Feed RSS

Il codice di oggi non è tanto, ma contiene diverse nozioni che vale la pena approfondire insieme: diamo quindi uno sguardo alla classe GenericDialog, da cui estenderemo gli altri avvisi, iniziando dal costruttore:

public GenericDialog() {}

Come possiamo vedere chiaramente, questo costruttore non fa assolutamente nulla ma è necessario per istanziare il nostro oggetto: omettendolo, potremmo trovarci di fronte ad un crash originato proprio dalla sua mancanza come, ad esempio, questo:

java.lang.InstantiationException: can't instantiate class [...]; no empty constructor

Passiamo quindi all’interfaccia, che ci definisce cosa fare in caso di click sui bottoni (per ora ne abbiamo soltanto due, ma possiamo aggiungere il terzo, nel caso ci servisse): questo componente ci serve per poter dialogare con l’Activity chiamante in tranquillità: non ci sono leak di sorta perché questo tipo di Fragment deve per forza essere attaccato all’Activity ed è proprio per questo motivo che controlliamo che l’Activity che richiama il Dialog viene controllata nell’evento onAttach().

Se ci spostiamo quindi nell’oggetto di tipo DialogInterface.OnClickListener che non fa altro che richiamare i metodi dell’interfaccia passando i dati richiesti.

C’è tuttavia un aspetto interessante che non abbiamo ancora esplorato ed è il metodo getValueFrom:

protected <T> T getValueFrom (Bundle inputBundle, String key, T defaultValue) {
if(inputBundle != null && inputBundle.containsKey(key)) {
return (T) inputBundle.get(key);
} else {
return defaultValue;
}
}

facendo uso dei generics di Java, controlliamo in un solo punto che il Bundle esista e che contenga la chiave che ci interessa, passando un valore di default dello stesso tipo T ritornato. Grazie a questo metodo, possiamo evitare di specificare un parametro di ritorno ma ci addentriamo in un territorio decisamente pericoloso: se non facciamo attenzione a come usiamo questo metodo, il rischio di incorrere in eccezioni di casting tra le classi è veramente alto!

Vediamo quindi come estendere questa classe e creare un oggetto che possiamo utilizzare per avvisare l’utente, prendendo come esempio la classe LocationConfirmationDialog.

Analizzando il codice di questo sorgente, riusciamo subito ad intravedere due peculiarità strettamente correlate tra loro: la prima è che salviamo la località dell’utente nell’onSaveInstanceState e la seconda è che la recuperiamo nel metodo onCreateDialog, dove creiamo di fatto l’AlertDialog. Perché tutto questo giro?

Andiamo con ordine e spieghiamo perché abbiamo deciso di racchiudere l’AlertDialog in un DialogFragment: il primo componente, un po’ come accade all’AsyncTask, non sopravvive al cambiamento di configurazione (come, ad esempio - ma non solo, la rotazione del dispositivo) e ha quindi bisogno di un componente che se ne occupi. Il DialogFragment è stato pensato proprio per questo motivo: come tutti i Fragment, supporta i cambiamenti di configurazione e non abbiamo quindi bisogno di ricrearlo, si occuperà il sistema di richiamare il metodo onCreateDialog tutte le volte che sarà necessario.

Abbiamo appena detto che il DialogFragment è in grado di sopravvivere alla rotazione ma i dati variabili che specifichiamo all’interno di esso, non lo sono. Per questo motivo, dobbiamo salvare i nostri dati nell’onSaveInstanceState e ripristinarli successivamente durante la creazione dell’AlertDialog.

Come ultimo punto, diamo uno sguardo alla nostra WeatherActivity, nella quale abbiamo implementato l’interfaccia e, soprattutto, abbiamo mostrato il nostro Dialog, in maniera leggermente diversa rispetto a come avremmo solitamente fatto:

LocationConfirmationDialog dialog = new LocationConfirmationDialog();
dialog.setLocation(location)
.show(getFragmentManager(), C.LOCATION_CONFIRMATION_DIALOG_TAG);

Perché il metodo show() è così differente rispetto a quello dell’AlertDialog? Essendo il DialogFragment un Fragment a tutti gli effetti (eredita direttamente da quest’ultimo), abbiamo bisogno di un FragmentManager per poterlo gestire e, in aggiunta, di un tag, per poterlo identificare.

Come spesso facciamo, abbiamo volutamente lasciato qualcosa di incompleto nel codice: di cosa si tratta questa volta?

Siamo giunti anche oggi alla fine di questo DevCorner e vi diamo appuntamento alla prossima settimana, ricordandovi che il nostro forum è sempre aperto a nuove (e vecchie) discussioni.


Buona programmazione a tutti!