Een evenementbus implementeren met LiveData

Wat je gaat creëren

Bij de laatste Google I / O bracht het Android-team een ​​reeks krachtige Android-architectuurcomponenten uit. Ze noemen het:

Een verzameling bibliotheken die u helpen robuuste, testbare en onderhoudbare apps te ontwerpen. Begin met klassen voor het beheer van de levensduur van uw UI-component en de verwerking van persistentiegegevens.

Als je er nog niets van hebt vernomen, wordt je ten zeerste aangeraden om onze geweldige serie hier te bekijken op Envato Tuts + over Android Architecture Components van Tin Megali. Zorg ervoor dat je erin gaat duiken! 

In deze zelfstudie laat ik u zien hoe u de Actuele gegevens componenten van de Android Architectural Components om een ​​evenementenbus te maken. Een gebeurtenisbus kan worden gebruikt om effectief te communiceren tussen Android-componenten of tussen lagen van uw toepassing, bijvoorbeeld communiceren met een Activiteit van een IntentService dat een bestand klaar is met downloaden. 

We zullen een zeer eenvoudige app bouwen die een IntentService om wat werk te doen - van een Activiteit. Onze IntentService zal dan terug communiceren naar de Activiteit wanneer het werk is voltooid. Ons communicatiekanaal komt van de Actuele gegevens bibliotheek. 

voorwaarden

Als je deze zelfstudie wilt kunnen volgen, heb je het volgende nodig:

  • Android Studio 3.0 of hoger
  • Kotlin-plug-in 1.1.51 of hoger
  • een basiskennis van de Android Architectural Components (met name de Actuele gegevens component)
  • een basiskennis van een evenementenbus

Je kunt ook alle ins en outs van de Kotlin-taal leren in mijn Kotlin From Scratch-serie.

  • Kotlin From Scratch: variabelen, basistypen en arrays

    Kotlin is een moderne programmeertaal die compileert met Java bytecode. Het is gratis en open source en belooft om het coderen voor Android nog leuker te maken.
    Chike Mgbemena
    Kotlin
  • Kotlin from Scratch: Klassen en objecten

    Maak kennis met objectgeoriënteerd programmeren in Kotlin door te leren over klassen: constructors en eigenschappen, casting en geavanceerde klassenfuncties.
    Chike Mgbemena
    Kotlin

1. Maak een Android Studio-project

Start Android Studio 3 en maak een nieuw project met een lege activiteit genaamd Hoofdactiviteit

2. Voeg de levenscycluscomponenten toe

Nadat u een nieuw project hebt gemaakt, geeft u de Levenscyclus en de Actuele gegevens artefacten in uw app-modules build.gradle. Merk op dat vanaf dit moment de nieuwe architectonische componenten zich nu in een stabiele versie bevinden. Dit betekent dus dat je ze kunt gaan gebruiken in productie-apps. 

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

Deze artefacten zijn beschikbaar in de Maven-repository van Google. 

allprojects repositories google () jcenter ()

Door de afhankelijkheden toe te voegen, hebben we stap voor stap geleerd hoe we de bibliotheek kunnen vinden. Vergeet niet om uw project te synchroniseren nadat u ze hebt toegevoegd. 

3. Maak het LifecycleOwner Activiteitsubklasse

Hier onze Hoofdactiviteit implementeert de LifecycleOwner interface. 

import android.arch.lifecycle.Lifecycle importeren 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) overschrijfplezier onCreate (savedInstanceState: Bundle?) super .onCreate (savedInstanceState) setContentView (R.layout.activity_main) register.handleLifecycleEvent (Lifecycle.Event.ON_CREATE) override fun getLifecycle (): Lifecycle = registry override plezier onStart () super.onStart () registry.handleLifecycleEvent (Lifecycle. Event.ON_START) overschrijven plezier 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) 

Onze activiteit behandelt eenvoudigweg de standaard activiteitscyclusevenementen. In elk van de levenscyclusgebeurtenissen roept het de registry.handleLifecycleEvent (), de bijbehorende gebeurtenis doorgeven als een parameter.   

4. Maak de lay-out

We hebben gewoon een Knop die de service activeert. EEN Tekstweergave (standaard onzichtbaar) toont de tekst "Werk voltooid!" wanneer de service communiceert met onze Hoofdactiviteit

  

5. Initialiseer de widgets

We hebben onze verklaard doWorkButton en resultTextView eigenschappen binnen de Hoofdactiviteit klasse met de lateinit modifier. We initialiseren ze vervolgens in de onCreate () methode. Anytime de doWorkButton is geklikt, we deactiveren het (om te voorkomen dat er meerdere keren op de knop wordt geklikt) en onze te starten MyIntentService (daar komen we binnenkort bij). 

class MainActivity: AppCompatActivity (), LifecycleOwner private lateinit var doWorkButton: Button 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. Maak de aangepaste gebeurtenisklasse

We maken gewoon een eenvoudige event message-klasse die we willen doorgeven aan de evenementenbus (of Actuele gegevens). 

dataclass CustomEvent (val eventProp: String)

U kunt desgewenst meer eigenschappen aan deze klasse toevoegen. 

7. Dienstimplementatie

We hebben een IntentService geïmplementeerd genaamd MyIntentService. Onthoudt dat IntentService leeft buiten het activiteitenbereik en heeft een achtergrondthread, dus het wordt aanbevolen om tijdrovende taken uit te voeren, zoals het downloaden of ophalen van externe gegevens via een API erin.  

Merk echter op dat in Android 8.0 als u uw niet maakt IntentService een voorgrondservice door gebruik te maken van startForeground (), het Android-systeem staat niet toe dat uw service langer dan 1 minuut wordt uitgevoerd, anders wordt deze onmiddellijk gestopt. Dit mechanisme is om systeembronnen zoals de levensduur van de batterij efficiënt te beheren. Als uw app Android 8.0 target, wordt u geadviseerd om de JobIntentService te gebruiken. 

import android.app.IntentService import android.arch.lifecycle.MutableLiveData import android.content.Intent import android.os.SystemClock class MyIntentService: IntentService ("MyIntentService") begeleidend object var BUS = MutableLiveData() override fun onHandleIntent (intent: Intent?) // werk simuleren SystemClock.sleep (3000) // aannemen dat werk is gedaan val event = CustomEvent ("value") if (BUS.hasActiveObservers ()) BUS.postValue (event) else // show notification

We maken een naamloos begeleidend object waarvan de begeleidende klasse is MyIntentService. Dit begeleidende object heeft een eigenschap genaamd BUS, wat een voorbeeld is van MutableLiveData.  Vergeet niet dat begeleidende objecten eenlingen zijn, dus dit betekent dat slechts één exemplaar van BUS bestaat. We hebben ook onze CustomEvent als een typeargument voor de generieke MutableLiveData klasse. 

Vergeet niet dat de MutableLiveData class is een subklasse van Actuele gegevens-en heeft een methode genaamd postValue () dat kan worden aangeroepen vanuit een achtergrondthread. 

openbare klasse MutableLiveData breidt LiveData uit @Override public void postValue (T-waarde) super.postValue (waarde);  @Override public void setValue (T-waarde) super.setValue (waarde); 

Binnen onHandleIntent (), we hebben onze bedrijfslogica. Onthoud dat deze methode wordt aangeroepen op een achtergrondthread (een van de grootste verschillen tussen een IntentService en een normaal Service). De IntentService eindigt direct vanzelf wanneer het onHandleIntent () methode beëindigt zijn taak.  

In ons geval simuleren we werk dat gedaan wordt (dit werk kan een bestand downloaden of communiceren met een API op afstand) door de huidige thread gedurende 30 seconden te slapen. We hebben vervolgens gecontroleerd of onze BUS heeft actieve waarnemers die de hasActiveObservers () methode. Als er een is, notificeer en verstuur je ons evenementbericht met behulp van de methode postValue (), of anders kunnen we eenvoudig een melding weergeven (dit was niet terloops gecodeerd in het voorbeeld hierboven). 

Vergeet niet om de service op te nemen in uw manifestbestand.

8. Implementatie van de waarnemer

We hebben ten minste één waarnemer nodig voor ons mechanisme om nuttig te zijn. Dus binnen de Hoofdactiviteit klas, gaan we een anonieme waarnemer inschrijven. 

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

Binnen in de onCreate () van Hoofdactiviteit, we hebben de evenementbus BUS van MyIntentService. Daarna registreerden we een waarnemer voor de gebeurtenisbus (d.w.z.. Actuele gegevens) de ... gebruiken acht () methode. Vervolgens hebben we een anonieme waarnemer geregistreerd en geinlinieerd, met behulp van de Hoofdactiviteit zoals LifecycleOwner. Deze anonieme waarnemer krijgt een melding wanneer een van de volgende dingen gebeurt:

  • Er zijn al gegevens beschikbaar in de Actuele gegevens wanneer het inschrijft. 
  • De gegevens in de Actuele gegevens wordt aangepast. 

Wanneer een van deze zich voordoet, krijgen we de evenement data (van de Actuele gegevens) op de hoofdtoepassingsdraad als invoer voor de lambda. We doen dan het volgende in het lichaam van de lambda:

  • Maak de resultTextView zichtbaar.
  • Schakel de doWorkButton.
  • Log onze aangepaste evenementeigenschap aan eventProp waarde voor Logcat.

Onthoud het volgende over Actuele gegevens:

  • Wanneer een nieuwe waarnemer is gehecht aan onze Actuele gegevens na een configuratiewijziging, Actuele gegevens stuurt de laatste gegevens die het heeft ontvangen naar de waarnemer - zelfs zonder dat we dit expliciet hebben aangegeven. Met andere woorden, het doet dit automatisch. 
  • Wanneer de LifecycleOwner wordt vernietigd, wordt de waarnemer automatisch afgemeld. 
  • Tenslotte, Actuele gegevens is een waarneembaar dat levenscyclusbewust is. Volgens de documenten:
LiveData is een waarneembare gegevenshouderklasse. Anders dan een gewone waarneembaar, is LiveData levenscyclusbewust, wat betekent dat het de levenscyclus van andere app-componenten respecteert, zoals activiteiten, fragmenten of services. Dit bewustzijn zorgt ervoor dat LiveData alleen app-componentwaarnemers die zich in een actieve levenscyclusstatus bevinden, bijwerkt.

9. Testen van de app

Eindelijk kunt u de app gebruiken! Klik op de Werken knop en na 30 seconden ziet u het resultaat. 

U kunt de volledige broncode verkrijgen via onze GitHub-repo.

Conclusie

In deze zelfstudie leer je hoe je de. Gemakkelijk kunt gebruiken Actuele gegevens componenten van de Android Architectural Components om een ​​gebeurtenisbus te maken - om effectief te communiceren met componenten van uw app. 

Ik neem aan dat u op de hoogte bent van andere bibliotheken die u voor hetzelfde doel kunt gebruiken, zoals Android LocalBroadcastManager of de populaire greenrobot EventBus om een ​​gebeurtenisbus in uw Android-applicatie te implementeren. Je kunt zien dat het gebruik van de Actuele gegevens in plaats daarvan heeft u de voorkeur - omdat u geen boilerplate of uitgebreide code hoeft te schrijven, en Actuele gegevens biedt u betere flexibiliteit. 

Voor meer informatie over codering voor Android, bekijk enkele van onze andere cursussen en tutorials hier op Envato Tuts+!