Impara Java per lo sviluppo Android Inner Classes

In questo tutorial, acquisirai familiarità con il concetto di classi interne in Java: quelle classi la cui portata e definizione sono comprese in un'altra classe. Imparerai anche a conoscere le classi interne anonime, che vengono utilizzate abbastanza frequentemente durante lo sviluppo con l'SDK di Android.

Le applicazioni Android sono scritte in Java, un linguaggio di programmazione orientato agli oggetti. In questo tutorial, imparerai a conoscere le classi interne, quando e perché utilizzarle e come funzionano. Imparerai anche come creare nuovi oggetti dinamicamente usando le classi interne anonime.

Cosa ti serve

Tecnicamente, non hai bisogno di strumenti per completare questo tutorial, ma sicuramente ti serviranno per sviluppare applicazioni Android.

Per sviluppare applicazioni Android (o qualsiasi altra applicazione Java, per quella materia), è necessario un ambiente di sviluppo per scrivere e creare applicazioni. Eclipse è un ambiente di sviluppo molto popolare (IDE) per Java e l'IDE preferito per lo sviluppo Android. È liberamente disponibile per i sistemi operativi Windows, Mac e Linux.

Per le istruzioni complete su come installare Eclipse (incluse le versioni supportate) e l'SDK Android, consultare il sito Web degli sviluppatori Android.

Cos'è una classe interiore?

La maggior parte delle classi in Java sono classi di livello superiore. Queste classi e gli oggetti che definiscono sono indipendenti. È anche possibile creare classi nidificate per incapsulare e definire chiaramente oggetti subordinati che contano solo nel contesto della classe esterna. Le classi annidate sono chiamate classi interne.

Le classi interne possono avere tutte le caratteristiche di una classe regolare, ma il loro ambito è limitato. Le classi interne hanno un altro vantaggio: hanno accesso completo alla classe in cui sono nidificate: questa caratteristica rende le classi interne perfette per l'implementazione delle funzionalità dell'adattatore come gli iteratori.

Ecco un esempio di una classe di alto livello con due classi interne:

 Utente della classe pubblica // Campi utente, comprese le variabili di tipo LoginInfo e UserPreferences // Classe dei metodi utente Misc LoginInfo // Campi info accesso // Metodi di accesso / disconnessione // Accesso ai campi utente / metodi classe Preferenze // Utente campi preferenza // Trova / Imposta i metodi di preferenza // Ripristina il metodo di preferenze // Può accedere a Campi / metodi utente 

In questo esempio, la classe User ha due classi interne: LoginInfo e Preferenze. Sebbene tutti i dati e le funzionalità relativi all'utente possano essere definiti nella classe User, l'uso delle classi interne per compartimentare le funzionalità può rendere il codice più facile da leggere e conservare. Le classi interne LoginInfo e Preferences hanno anche accesso ai campi e ai metodi protetti / privati ​​disponibili all'interno della classe User, che potrebbero non avere altrimenti a causa della sicurezza, se fossero definiti come classi autonome.

È importante ricordare, tuttavia, che le classi interne esistono davvero solo per aiutare lo sviluppatore ad organizzare il codice; il compilatore tratta le classi interne come qualsiasi altra classe, tranne per il fatto che le classi interne hanno un ambito limitato e sono quindi legate alla classe con cui sono definite. Detto in un altro modo, non saresti in grado di utilizzare o istanziare le classi LoginInfo o Preferences eccetto con un'istanza della classe User, ma le classi interne potrebbero accedere a qualsiasi campo o metodo disponibile nella classe esterna User, se necessario.

Uso di classi nidificate statiche

Uno in particolare per le classi annidate è classi nidificate statiche. Una classe interna statica definisce un comportamento che non è legato a un'istanza di oggetto specifica, ma si applica a tutte le istanze. Ad esempio, potremmo aggiungere una terza classe nidificata, questa volta statica, alla classe User per controllare le funzionalità relative al server:

 Utente della classe pubblica // Campi utente, comprese le variabili di tipo LoginInfo e UserPreferences // Classe dei metodi utente Misc LoginInfo  public static class ServerInfo  // Le informazioni sul server si applicano a tutte le istanze dell'utente 

Poiché è pubblico, questa classe nidificata statica può essere istanziata utilizzando la seguente nuova istruzione:

 User.ServerInfo sInfo = new User.ServerInfo (); 

La classe esterna non deve essere istanziata per eseguire questa istanziazione, quindi l'uso del nome della classe. In quanto tale, una classe nidificata statica, a differenza di una classe nidificata non statica (nota anche come classe interna), non ha accesso ai membri della classe esterna - non possono nemmeno essere istanziati.

Il potere delle classi interiori anonime

Android utilizza le classi interne anonime con grande effetto. Le classi interne anonime sono fondamentalmente stenografia dello sviluppatore, consentendo allo sviluppatore di creare, definire e utilizzare un oggetto personalizzato tutto in una "linea". Potresti aver visto esempi dell'uso della classe interna anonima nel codice di esempio e non averlo nemmeno realizzato.
Per creare una classe interna anonima, fornisci solo il lato destro della definizione. Inizia con la nuova parola chiave, seguita dalla classe o dall'interfaccia che desideri estendere o implementare, seguita dalla definizione della classe. Questo creerà la classe e la restituirà come un valore che potrai usare per chiamare un metodo.
Quando usiamo una classe interna anonima, l'oggetto creato non viene assegnato un nome (quindi il termine anonimo). L'effetto collaterale, ovviamente, è che l'oggetto è usato usato una sola volta. Ad esempio, è comune utilizzare una classe interna anonima per costruire una versione personalizzata di un oggetto come valore di ritorno. Ad esempio, qui estendiamo la classe Truck (supponendo che sia definita altrove e abbia un campo chiamato mpg e due metodi, start () e stop ():

 Truck getTruck () return new Truck () int mpg = 3; void start () / * start implementazione * / void stop () / * stop implementation * /;  

Ora diamo un'occhiata ad esempi pratici di classi interne anonime usate in Android.

Utilizzo di una classe interna anonima per definire un listener

Gli sviluppatori Android spesso utilizzano classi interne anonime per definire listener specializzati, che registrano i callback per un comportamento specifico quando si verifica un evento. Ad esempio, per ascoltare i clic su un controllo View, lo sviluppatore deve chiamare il metodo setOnClickListener (), che accetta un singolo parametro: un oggetto View.OnClickListener.
Gli sviluppatori utilizzano abitualmente la tecnica anonima della classe interna per creare, definire e utilizzare il loro personalizzato View.OnClickListener, come segue:

 Button aButton = (Button) findViewById (R.id.MyButton); aButton.setOnClickListener (new View.OnClickListener () public void onClick (View v) // L'utente ha fatto clic sul mio pulsante, fa qualcosa qui!); 

Utilizzo di una classe interna anonima per avviare una discussione

Diamo un'occhiata ad un altro esempio. È abbastanza comune definire una nuova classe Thread, fornire l'implementazione del suo metodo run () e avviare quel thread, tutto in una volta:

 new Thread () public void run () doWorkHere ();  .inizio(); 

Utilizzando una classe interna denominata

L'utilizzo di classi interne anonime per gli ascoltatori in Android è così comune che è praticamente una seconda natura farlo. Perché, quindi, non vorresti usarli? Rispondiamo con un esempio ipotetico.
Diciamo che hai uno schermo con 100 pulsanti (abbiamo detto ipotetico, giusto?). Ora, diciamo che ogni pulsante, quando premuto, fa il la stessa identica cosa. In questo caso, ascolteremo solo i clic e tosteremo il testo dall'oggetto View passato (il testo mostrato sul pulsante su cui è stato fatto clic):
Ecco lo pseudo codice per farlo:

 Button [] buttons = getAllOneHundredButtonsAsArray (); per (Pulsante: pulsanti) button.setOnClickListener (new View.OnClickListener () public void onClick (Visualizza v) showToast (v.getText ()););  

Breve ed elegante, quindi cosa c'è di sbagliato in esso? Ad ogni iterazione, viene istanziato un nuovo oggetto OnClickListener. Dal momento che ognuno è esattamente lo stesso, non c'è una buona ragione per crearne 100. Invece, è possibile creare una singola classe interna, denominata, istanziarla una volta, quindi passarla al metodo setOnClickListener (). Per esempio:

 class MyActivity estende Activity public void myMethod () MyClickHandler handler = new MyClickHandler (); Button [] buttons = getAllOneHundredButtonsAsArray (); per (pulsante: pulsanti) button.setOnClickListener (gestore);  classe MyClickHandler implementa View.OnClickListener public void onClick (View v) showToast (((Button) v) .getText ());  

Se preferisci l'anonimato, puoi comunque assegnare una classe interna anonima a una variabile e usarla, in questo modo:

 class MyActivity estende Activity public void myMethod () View.OnClickListener handler = new View.OnClickListener () public void onClick (View v) showToast (((Button) v) .getText ()); ; Button [] buttons = getAllOneHundredButtonsAsArray (); per (pulsante: pulsanti) button.setOnClickListener (gestore);  

Il metodo dipende da te, ma tieni a mente i potenziali problemi di memoria e di prestazioni che potrebbero creare istanze di istanziazione di un gruppo di oggetti.

Una nota sulle sfumature

Questo tutorial è pensato per essere una guida introduttiva alle classi interne in Java. Ci sono considerazioni e sfumature di stile quando si utilizzano le classi interne in modi diversi e creativi. Oltre a ciò, è possibile esplorare ulteriormente per ulteriori informazioni sugli effetti interni e sulle differenze marginali delle prestazioni che possono essere visualizzate quando si utilizzano classi nidificate in modi diversi. Tutto questo, tuttavia, va ben oltre lo scopo di questo tutorial.

Una breve nota sulla terminologia

Sebbene abbiamo cercato di essere coerenti con la terminologia su classi interne e nidificate, la terminologia non è sempre coerente con varie risorse online e offline. I seguenti sono un elenco di termini dalla documentazione Sun / Oracle corrente, che è valida quanto qualsiasi per essere autorevole su Java:

  • Classe annidata: una classe definita all'interno di un'altra classe
  • Classe annidata statica: una classe statica definita all'interno di un'altra classe
  • Classe interiore: una classe nidificata non statica definita all'interno di un'altra classe
  • Classe interna locale: una classe definita all'interno di un metodo
  • Classe interiore anonima: una classe senza nome definita all'interno di un metodo

Confuso? È possibile utilizzare i metodi java.lang.Class chiamati isLocalClass () e isAnonymous () sulle classi istanziate per determinare un paio di queste proprietà. Un blog di Oracle tenta di chiarire anche la situazione con un bel diagramma di Venn.

Avvolgendo

Il linguaggio di programmazione Java supporta classi nidificate, consentendo allo sviluppatore una grande flessibilità nella definizione degli oggetti. Le classi interne possono essere utilizzate per organizzare le funzionalità di classe o per definire comportamenti specializzati che altrimenti richiederebbero allo sviluppatore di esporre dati di classe e funzionalità che in realtà non dovrebbero essere esposti. Le classi interne statiche possono essere utilizzate per definire campi e funzionalità che si applicano a tutte le istanze di una classe. Infine, le classi interne anonime forniscono una utile stenografia per gli sviluppatori che vogliono creare, definire e utilizzare un oggetto personalizzato tutto in una volta.