Implementazione di un bus eventi con LiveData

Cosa starai creando

All'ultimo Google I / O, il team di Android ha rilasciato una serie di potenti componenti di architettura Android. Lo chiamano:

Una raccolta di librerie che ti aiutano a progettare app robuste, testabili e manutenibili. Inizia con le classi per la gestione del ciclo di vita dei componenti dell'interfaccia utente e la gestione della persistenza dei dati.

Se non hai imparato a conoscerli, ti consigliamo vivamente di dare un'occhiata alle nostre fantastiche serie qui su Envato Tuts + su Componenti di architettura Android di Tin Megali. Assicurati di andare a fare immersioni! 

In questo tutorial, ti mostrerò come usare il LiveData componenti da Componenti architetturali Android per creare un bus eventi. È possibile utilizzare un bus eventi per comunicare in modo efficace tra i componenti Android o tra i livelli dell'applicazione, ad esempio comunicando con un Attività da un IntentService che un file ha finito di scaricare. 

Costruiremo un'applicazione molto semplice che attiva un IntentService fare un po 'di lavoro, da un Attività. Nostro IntentService quindi comunicherà nuovamente al Attività quando il lavoro è completato. Il nostro canale di comunicazione sarà dal LiveData biblioteca. 

Prerequisiti

Per poter seguire questo tutorial, avrai bisogno di:

  • Android Studio 3.0 o versioni successive
  • Plugin Kotlin 1.1.51 o successivo
  • una conoscenza di base dei componenti architettonici Android (in particolare il LiveData componente)
  • una conoscenza di base di un bus eventi

Puoi anche imparare tutti i dettagli del linguaggio Kotlin nella mia serie Kotlin From Scratch.

  • Kotlin From Scratch: variabili, tipi di base e matrici

    Kotlin è un linguaggio di programmazione moderno che viene compilato in bytecode Java. È gratuito e open source e promette di rendere la codifica per Android ancora più divertente.
    Chike Mgbemena
    Kotlin
  • Kotlin From Scratch: Classi e oggetti

    Ottieni un'introduzione alla programmazione orientata agli oggetti in Kotlin imparando a conoscere le classi: costruttori e proprietà, casting e funzioni di classe avanzate.
    Chike Mgbemena
    Kotlin

1. Creare un progetto per Android Studio

Avvia Android Studio 3 e crea un nuovo progetto con un'attività vuota chiamata Attività principale

2. Aggiungi i componenti del ciclo di vita

Dopo aver creato un nuovo progetto, specificare il Ciclo vitale e il LiveData artefatti nei moduli dell'app build.gradle. Si noti che al momento della stesura, i nuovi componenti architettonici sono ora in una versione stabile. Questo significa che puoi iniziare a usarli nelle app di produzione. 

dependencies implementation fileTree (dir: 'libs', include: ['* .jar']) implementazione "org.jetbrains.kotlin: kotlin-stdlib-jre7: $ kotlin_version" implementazione "com.android.support:appcompat-v7: 26.1.0 "implementazione" android.arch.lifecycle: runtime: 1.0.3 "implementazione" android.arch.lifecycle: extensions: 1.0.0 "

Questi artefatti sono disponibili nel repository Maven di Google. 

allprojects repositories google () jcenter ()

Aggiungendo le dipendenze, abbiamo insegnato a gradle come trovare la libreria. Assicurati di ricordare di sincronizzare il progetto dopo averlo aggiunto. 

3. Creare il LifecycleOwner Attività sottoclasse

Ecco il nostro Attività principale implementa il LifecycleOwner interfaccia. 

import android.arch.lifecycle.Lifecycle import android.arch.lifecycle.LifecycleOwner import android.arch.lifecycle.LifecycleRegistry import android.arch.lifecycle.Observer import android.content.Intent import android.os.Bundle import android.support.v7 .app.AppCompatActivity import android.view.View import android.widget.Button import android.widget.TextView class MainActivity: AppCompatActivity (), LifecycleOwner private val registry = LifecycleRegistry (this) override fun onCreate (savedInstanceState: Bundle?) super .onCreate (savedInstanceState) setContentView (R.layout.activity_main) registry.handleLifecycleEvent (Lifecycle.Event.ON_CREATE) override fun getLifecycle (): Lifecycle = registro override fun onStart () super.onStart () registry.handleLifecycleEvent (Lifecycle. Event.ON_START) override fun onResume () super.onResume () registry.handleLifecycleEvent (Lifecycle.Event.ON_RESUME) override fun onPause () super.onPause () registry.handleLifecycleEvent (Lifecycle.Event.ON_PAUSE)  override fun onStop () super.onStop () registry.handleLifecycleEvent (Lifecycle.Event.ON_STOP) override fun onDestroy () super.onDestroy () registry.handleLifecycleEvent (Lifecycle.Event.ON_DESTROY) 

La nostra attività gestisce semplicemente gli eventi del ciclo di vita delle attività standard. All'interno di ciascuno degli eventi del ciclo di vita, chiama il registry.handleLifecycleEvent (), passando l'evento corrispondente come parametro.   

4. Creare il layout

Abbiamo solo un Pulsante che attiva il servizio. UN TextView (invisibile per impostazione predefinita) mostra il testo "Lavoro completato!" quando il servizio comunica al nostro Attività principale

  

5. Inizializza i widget

Abbiamo dichiarato il nostro doWorkButton e resultTextView proprietà all'interno del Attività principale classe con il lateinit modificatore. Inizialmente li inizializziamo nel onCreate () metodo. Ogni volta che la doWorkButton viene cliccato, lo disabilitiamo (per evitare di fare clic sul pulsante più di una volta) e iniziare il nostro MyIntentService (ci arriveremo a breve). 

class MainActivity: AppCompatActivity (), LifecycleOwner private lateinit var doWorkButton: pulsante private lateinit var resultTextView: TextView override fun onCreate (savedInstanceState: Bundle?) // ... doWorkButton = findViewById (R.id.btn_download) doWorkButton.setOnClickListener doWorkButton. isEnabled = false resultTextView.visibility = View.INVISIBLE val serviceIntent = Intent (this, MyIntentService :: class.java) startService (serviceIntent) resultTextView = findViewById (R.id.tv_result) // ...

6. Creare la classe di evento personalizzata

Creiamo solo una semplice classe di messaggi di eventi che vogliamo trasferire sul bus eventi (o LiveData). 

classe di dati CustomEvent (val eventProp: String)

Puoi aggiungere più proprietà a questa classe se vuoi. 

7. Implementazione del servizio

Abbiamo implementato un IntentService chiamato MyIntentService. Ricordatelo IntentService vive al di fuori dell'ambito di attività e ha un thread in background, quindi si consiglia di eseguire attività dispendiose in termini di tempo come il download o il recupero di dati remoti tramite un'API al suo interno.  

Tuttavia, tieni presente che in Android 8.0 se non fai il tuo IntentService un servizio in primo piano usando startForeground (), il sistema Android non consente al servizio di funzionare più di 1 minuto, altrimenti verrà interrotto immediatamente. Questo meccanismo consente di gestire in modo efficiente le risorse di sistema, ad esempio la durata della batteria. Se la tua app ha come target Android 8.0, ti consigliamo di utilizzare invece JobIntentService. 

import android.app.IntentService import android.arch.lifecycle.MutableLiveData import android.content.Intent import android.os.SystemClock class MyIntentService: IntentService ("MyIntentService") oggetto companion var BUS = MutableLiveData() override fun onHandleIntent (intent: Intent?) // simula work SystemClock.sleep (3000) // supponendo che il lavoro sia eseguito val event = CustomEvent ("valore") if (BUS.hasActiveObservers ()) BUS.postValue (evento) else // mostra notifica

Creiamo un oggetto companion senza nome di cui è la classe companion MyIntentService. Questo oggetto associato ha una proprietà chiamata AUTOBUS, che è un'istanza di MutableLiveData.  Ricorda che gli oggetti complementari sono singoletti, quindi questo significa che solo una singola istanza di AUTOBUS esiste. Abbiamo anche passato il nostro CustomEvent come argomento di tipo al generico MutableLiveData classe. 

Ricorda che il MutableLiveData la classe è una sottoclasse di LiveData-e ha un metodo chiamato postValue () che può essere chiamato da un thread in background. 

Classe pubblica MutableLiveData estende LiveData @Override public void postValue (valore T) super.postValue (valore);  @Override public void setValue (valore T) super.setValue (valore); 

Dentro onHandleIntent (), abbiamo la nostra logica aziendale. Ricorda che questo metodo è chiamato su un thread in background (una delle maggiori differenze tra an IntentService e un normale Servizio). Il IntentService finisce immediatamente da solo quando il onHandleIntent () il metodo finisce il suo lavoro.  

Nel nostro caso, simuliamo il lavoro svolto (questo lavoro può essere un download di file o la comunicazione con un'API remota) dormendo il thread corrente per 30 secondi. Abbiamo quindi controllato se il nostro AUTOBUS ha qualche osservatore attivo che usa il hasActiveObservers () metodo. Se ce ne sono, notifica e passa loro il nostro messaggio di evento usando il metodo postValue (), oppure possiamo semplicemente mostrare una notifica (questo non è stato codificato nell'esempio di cui sopra per brevità). 

Ricorda di includere il servizio nel file manifest.

8. Implementazione degli osservatori

Abbiamo bisogno di almeno un osservatore perché il nostro meccanismo sia utile. Quindi dentro Attività principale classe, stiamo per sottoscrivere un osservatore anonimo. 

class MainActivity: AppCompatActivity (), LifecycleOwner // ... override fun onCreate (savedInstanceState: Bundle?) // ... MyIntentService.BUS.observe (this, Observer event -> resultTextView.visibility = View.VISIBLE downloadButton.isEnabled = true Log.d ("MainActivity", event? .EventProp)) // ...

Dentro il onCreate () di Attività principale, abbiamo il bus per gli eventi AUTOBUS a partire dal MyIntentService. Quindi abbiamo registrato un osservatore per il bus degli eventi (ad es. LiveData) usando il osservare() metodo. Successivamente, abbiamo registrato e sottolineato un osservatore anonimo, usando il Attività principale come LifecycleOwner. Questo osservatore anonimo viene avvisato quando si verifica uno dei seguenti eventi:

  • Vi sono già dati disponibili in LiveData quando si abbona. 
  • I dati all'interno del LiveData viene modificato. 

Quando uno di questi si verifica, otteniamo il evento dati (dal LiveData) sul thread dell'applicazione principale come input per la lambda. Facciamo quindi quanto segue all'interno del corpo di Lambda:

  • Fare il resultTextView visibile.
  • Abilita il doWorkButton.
  • Registra la nostra proprietà evento personalizzata eventProp valore per Logcat.

Ricorda quanto segue LiveData:

  • Quando un nuovo osservatore è attaccato al nostro LiveData dopo una modifica alla configurazione, LiveData invierà gli ultimi dati ricevuti all'osservatore, anche senza che noi glielo diciamo esplicitamente. In altre parole, lo fa automaticamente. 
  • Quando il LifecycleOwner viene distrutto, l'osservatore verrà automaticamente annullato. 
  • Finalmente, LiveData è un osservabile che è consapevole del ciclo di vita. Secondo i documenti:
LiveData è una classe di data holder osservabile. A differenza di un normale osservabile, LiveData è consapevole del ciclo di vita, nel senso che rispetta il ciclo di vita di altri componenti dell'app, come attività, frammenti o servizi. Questa consapevolezza assicura che LiveData aggiorni solo gli osservatori di componenti di app che si trovano in uno stato di ciclo di vita attivo.

9. Testare l'app

Finalmente puoi eseguire l'app! Clicca il Lavora pulsante e dopo 30 secondi, vedrai il risultato. 

Puoi ottenere il codice sorgente completo dal nostro repository GitHub.

Conclusione

In questo tutorial, hai imparato come usare facilmente il LiveData componenti da Componenti architetturali Android per creare un bus eventi, in modo da comunicare in modo efficace con i componenti della tua app. 

Presumo che tu sia a conoscenza di altre librerie che puoi utilizzare per lo stesso scopo, come Android LocalBroadcastManager o il popolare greenBot EventBus per implementare un bus eventi nella tua applicazione Android. Puoi vedere che usando il LiveData preferibilmente è preferibile a loro, perché eviti di scrivere codice standard o verbale e LiveData ti offre una maggiore flessibilità. 

Per ulteriori informazioni sulla codifica per Android, consulta alcuni dei nostri altri corsi e tutorial qui su Envato Tuts+!