Il pericolo di usare kotlin.syntetic for block in layout

Foto di Justin Chrn su Unsplash

Ora, con l’avvento di Kotlin nello sviluppo per Android, è apparso uno strumento utile per legare le viste da xml-layout alla classe. Questo è kotlinx.android.synthetic. Non c’è più bisogno di usare il metodo findViewById(). È sufficiente scrivere il valore dell’id, che è specificato nell’xml, e si potrebbe usare la vista nella classe.Ci sono molti articoli su questo, come la descrizione ufficiale per esempio. Ma ci possono essere problemi non ovvi con l’uso del tag <include> nel layout. Creiamo un piccolo esempio e proviamo a mostrare un caso simile.

L’applicazione di prova è una lista con due elementi, ognuno dei quali contiene un pulsante con un testo. All’inizio creeremo i layout per gli elementi – item1.xml e item2.xml. Lo sfondo dietro il pulsante ha colori diversi per una visibilità più utile.

Facciamo in modo che i pulsanti negli elementi abbiano lo stesso id “button”. È una cosa importante.

Poi aggiungiamo questi elementi a main_layout con l’aiuto del tag <include>:

Ora usiamolo nella classe come layout:

Eseguiamo l’applicazione per ottenere il seguente risultato:

Identificazione del problema

Ora facciamo una piccola funzione, e cambiamo il testo dei pulsanti nel codice. Ci sarà un nuovo testo “Changed Text First Item” per il primo pulsante, e “Changed Text Second Item” per il secondo. Per il binding ai pulsanti si userà kotlinx.synthetic con alias:

import kotlinx.android.synthetic.main.item1.button as button1
import kotlinx.android.synthetic.main.item2.button as button2

E’ ovviamente button1 è visto da item1.xml, button2 da item2.xml. Poi cambiamo il testo su OnCreate:

Eseguiamo l’applicazione e vediamo il risultato:

Oops! Non è quello che ci aspettavamo. Il testo del primo pulsante è stato cambiato al testo che è stato scritto per il secondo, e il testo del secondo pulsante non è cambiato assolutamente.

Spiegazione del problema

Cerchiamo di capire qual è la ragione di questo risultato. Ora vediamo come funziona il lavoro sintetico sotto il cofano. Per questo decompiliamo la classe Kotlin in Java (Show Kotlin Bytecode -> Decompile for AndroidStudio). Ora MainActivity assomiglia a questo:

Ora possiamo capire come funziona il sintetico. L’attività ha HashMap, che usa l’id della vista come chiave e l’oggetto della vista come valore. È riempita da un’inizializzazione pigra. Nel nostro caso, la prima chiamata a button1 cerca il valore della HashMap con la chiave id = R.id.button. Poiché non c’è ancora un tale valore, il metodo aggiunge una coppia alla mappa, dove id come chiave e un oggetto-pulsante da item1 come valore. Come risultato, il testo per il primo pulsante viene applicato con successo.

La chiamata a button2, che ha anche id = R.id.button, controlla il valore della mappa per questa chiave, trova il nostro primo View (il pulsante dal primo elemento), e lo riempie con il valore del secondo pulsante. Come risultato, il primo pulsante cambia testo due volte, il secondo non una volta

Soluzione del problema

Come prima, potete usare id diversi per ogni vista. Ma se non è utile, puoi tornare a findViewById:

Eseguiamo l’applicazione e vediamo il risultato:

Ora funziona correttamente!

Conclusione

Le nuove caratteristiche del linguaggio danno un sacco di utilità, ma si dovrebbe capire come funziona per evitare problemi.

Grazie per aver letto questo articolo! Spero che ti sia utile

.

Lascia un commento