Impara Java per lo sviluppo Android Altro su Inner Classes

Questa breve lezione discute una serie di suggerimenti per lavorare con le classi interne in Java. Questa lezione fa parte di una serie continua di tutorial per gli sviluppatori che stanno imparando Java per sviluppare applicazioni Android.

Cosa sono le classi interne (anonime)?

In Java, le classi possono essere annidate l'una nell'altra al fine di organizzare dati e funzionalità in modo ordinato. Le classi interne anonime sono fondamentalmente stenografia dello sviluppatore, consentendo allo sviluppatore di creare, definire e utilizzare un oggetto personalizzato tutto in una volta. Le classi interne anonime sono frequentemente utilizzate in Android per definire i gestori per i controlli, definire e lanciare nuovi thread e creare e restituire oggetti personalizzati in metodi senza codice ingombrante con impostazioni non necessarie.

Per una discussione approfondita delle classi interne e nidificate, comprese le classi interne anonime, consultare il nostro tutorial chiamato Learn Java per Android Development: Inner Classes

Accesso alle variabili esterne con la parola chiave finale

A volte si desidera accedere alle informazioni disponibili al di fuori della classe interna. Considera il seguente esempio. Hai una schermata con due controlli: un pulsante e una vista testo. Ogni volta che l'utente fa clic sul controllo Button, il controllo TextView viene aggiornato con l'ora corrente. All'interno della classe Attività associata a questo layout, tu poteva implementare questa funzionalità come segue:

 Button myButton = (Button) findViewById (R.id.ButtonToClick); myButton.setOnClickListener (new View.OnClickListener () public void onClick (Visualizza v) SimpleDateFormat formatter = new SimpleDateFormat ("h: mm: ss a"); String strWhen = formatter.format (new Date ()); TextView myTextview = (TextView) findViewById (R.id.TextViewToShow); myTextview.setText ("Clicked at" + strWhen);); 

Il codice precedente verrà eseguito e si comporterà come previsto. Tuttavia, diciamo che volevi davvero dichiarare il controllo TextView al di fuori della classe interna e usarlo anche per altri scopi. Forse dovresti provare a farlo invece:

 TextView myTextview = (TextView) findViewById (R.id.TextViewToShow); Button myButton = (Button) findViewById (R.id.ButtonToClick); myButton.setOnClickListener (new View.OnClickListener () public void onClick (Visualizza v) SimpleDateFormat formatter = new SimpleDateFormat ("h: mm: ss a"); String strWhen = formatter.format (new Date ()); myTextview. setText ("Clicked at" + strWhen);); 

Sfortunatamente, questo non verrà compilato. Invece, otterrai l'errore di compilazione "Impossibile riferirsi a una variabile non finale myTextview all'interno di una classe interna definita in un metodo diverso". Come suggerisce l'errore, ciò che devi fare è rendere definitiva la variabile TextView, in modo che sia accessibile all'interno del metodo onClick () della classe interna:

 TextView finale myTextview = (TextView) findViewById (R.id.TextViewToShow); Button myButton = (Button) findViewById (R.id.ButtonToClick); myButton.setOnClickListener (new View.OnClickListener () public void onClick (Visualizza v) SimpleDateFormat formatter = new SimpleDateFormat ("h: mm: ss a"); String strWhen = formatter.format (new Date ()); myTextview. setText ("Clicked at" + strWhen);); 

Questo codice verrà effettivamente compilato ed eseguito come previsto.

Lavorare con le variabili finali in Java

Rendendo definitiva la variabile TextView nell'esempio precedente, l'hai resa disponibile per la classe interna anonima (o per qualsiasi classe interna definita all'interno del suo ambito, peraltro). Ecco alcune altre cose da sapere sulle variabili finali:

  • Non è possibile modificare il valore (valore r) di una variabile finale. Ad esempio, se si è tentato di assegnare la variabile myTextview a un altro controllo all'interno del metodo onClick () della classe interna, si otterrebbe l'errore di compilazione "La variabile locale finale myTextview non può essere assegnata, poiché è definita in un tipo di inclusione. ”
  • Puoi chiamare i metodi di una variabile finale, purché tu abbia accesso. Questo è ciò che ci consente di effettuare la chiamata al metodo setText () di TextView. Questo non cambia il valore della variabile myTextview, semplicemente cambia ciò che viene visualizzato sullo schermo, una differenza sottile ma importante. (La ragione di ciò è semplicemente che il riferimento all'oggetto non può cambiare, ma l'oggetto stesso può cambiare attraverso i suoi metodi).
  • Non è necessario conoscere il valore di una variabile finale in fase di compilazione, mentre una variabile statica è nota al momento della compilazione.
  • La parola chiave finale viene spesso associata alla variabile statica (un campo o una variabile legata a tutte le istanze di una classe, anziché una singola istanza) per creare una costante da utilizzare all'interno dell'applicazione, come in: pubblico finale statico String DEBUG_TAG, utilizzato per scopi di registrazione LogCat in tutta l'attività.

Inner Classes e la variabile "This"

In Java, puoi usare lo speciale Questo riferimento per fare riferimento all'istanza specifica di un oggetto. Quindi cosa succede quando hai una classe con una classe interiore o, per quella materia, una classe interiore anonima? Bene, la classe interna può accedere alla speciale questa istanza della classe che li contiene, e ha anche questo riferimento. Per accedere a questa istanza per la classe interna, usa semplicemente questa sintassi. Per accedere a questa istanza della classe che include, è necessario virare sul nome della classe che racchiude, quindi un punto, quindi questo. Per esempio:

 MyEnclosingClass.this 

Dai un'occhiata alla piena implementazione della classe interna anonima, come discusso sopra, nel contesto completo della sua classe di chiusura, qui chiamata ClassChaosActivity:

 pacchetto com.androidbook.classchaos; import java.text.SimpleDateFormat; import java.util.Date; importare android.app.Activity; importare android.os.Bundle; import android.util.Log; importa android.view.View; importa android.widget.Button; import android.widget.TextView; public class ClassChaosActivity estende Activity public static final String DEBUG_TAG = "MyLoggingTag"; / ** Chiamato quando l'attività viene creata per la prima volta. * / @Override public void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.main); TextView finale myTextview = (TextView) findViewById (R.id.TextViewToShow); Button myButton = (Button) findViewById (R.id.ButtonToClick); myButton.setOnClickListener (new View.OnClickListener () public void onClick (Visualizza v) SimpleDateFormat formatter = new SimpleDateFormat ("h: mm: ss a"); String strWhen = formatter.format (new Date ()); myTextview. setText ("Clicked at" + strWhen); Log.v (DEBUG_TAG, "questo Nome classe:" + this.getClass (). getName ()); Log.v (DEBUG_TAG, "questa estende l'interfaccia denominata:" + this. getClass (). getInterfaces () [0] .getName ()); Log.v (DEBUG_TAG, "questo nome di classe Enclosing:" + this.getClass (). getEnclosingClass (). getName ()); Log.v (DEBUG_TAG , "this Is anonymous class?" + this.getClass (). isAnonymousClass ()); Log.v (DEBUG_TAG, "ClassChaosActivity.this Nome classe:" + ClassChaosActivity.this.getClass (). getName ()); Log. v (DEBUG_TAG, "ClassChaosActivity.this Super Class name:" + ClassChaosActivity.this.getClass (). getSuperclass (). getName ()); Log.v (DEBUG_TAG, "ClassChaosActivity.this È una classe anonima?" + ClassChaosActivity.this .getClass (). isAnonymousClass ()););  

L'output del registro per il clic del pulsante procede come segue:

 10-24 18: 18: 53.075: VERBOSE / MyLoggingTag (751): questo Nome classe: com.androidbook.classchaos.ClassChaosActivity $ 1 10-24 18: 18: 53.085: VERBOSE / MyLoggingTag (751): estende l'interfaccia denominata: android .view.View $ OnClickListener 10-24 18: 18: 53.085: VERBOSE / MyLoggingTag (751): questo nome classe Enclosing: com.androidbook.classchaos.ClassChaosActivity 10-24 18: 18: 53.095: VERBOSE / MyLoggingTag (751): questa è una classe anonima? true 10-24 18: 18: 53.095: VERBOSE / MyLoggingTag (751): ClassChaosActivity.this Nome classe: com.androidbook.classchaos.ClassChaosActivity 10-24 18: 18: 53.105: VERBOSE / MyLoggingTag (751): ClassChaosActivity.this Super Nome classe: android.app.Activity 10-24 18: 18: 53.105: VERBOSE / MyLoggingTag (751): ClassChaosActivity.questa classe anonima? falso 

Come puoi vedere, questa parola chiave si riferisce alla classe "più vicina", la classe interiore. Sebbene la classe interna sia anonima, Java gli fornisce un numero ClassChaosActivity $ 1 per tenerne traccia. Sebbene non sia utile agli sviluppatori di per sé, ciò dimostra che la classe interna anonima è trattata internamente come qualsiasi altra classe. Nel frattempo, accediamo all'istanza della classe che include la sintassi ClassChaosActivity.this.

Conclusione

In questa breve lezione hai appreso diversi suggerimenti per aiutarti a usare le classi interiori e le classi interiori anonime con maggiore abilità. Hai imparato che le classi interne possono accedere a variabili dichiarate al di fuori del loro ambito, a condizione che le variabili siano contrassegnate come finali e quindi immutabili. Hai anche imparato a conoscere la sintassi speciale relativa a questa parola chiave quando si tratta di accedere ai dati delle istanze delle classi interne e ai dati delle istanze della classe che li contengono.

Riguardo agli Autori

Gli sviluppatori mobili Lauren Darcey e Shane Conder hanno coautore diversi libri sullo sviluppo di Android: un libro di programmazione approfondito intitolato Sviluppo di applicazioni wireless Android e Sams TeachYourself Sviluppo di applicazioni Android in 24 ore. Quando non scrivono, passano il loro tempo a sviluppare software mobile presso la loro azienda ea fornire servizi di consulenza. Possono essere contattati via email a [email protected], tramite il loro blog su androidbook.blogspot.com e su Twitter @androidwireless.

Hai bisogno di più aiuto nella scrittura di app per Android? Consulta i nostri ultimi libri e risorse!