Mit Lambda-Ausdrücken können Sie Boilerplate-Code aus Ihren Projekten entfernen und große Datenmengen problemlos verarbeiten. Erfahren Sie, wie Sie mit diesem detaillierten Blick auf die Java 8-Funktionen, die Sie heute in Ihren Android-Projekten verwenden können, beginnen.
Java 8, das bereits im März 2014 debütierte, war für die Programmiersprache ein großer Schritt nach vorne und führte eine Liste mit Funktionen ein, die das Programmieren in Java einfacher und prägnanter machen als je zuvor.
Android-Entwickler würden die Vorteile dieser Funktionen leider nicht für eine Weile spüren, da Google mit Jack (Java Android Compiler Kit) experimentierte, Java 8 auf die Android-Plattform zu bringen, bevor er Jack für die native Unterstützung von Java 8 in Android Studio ablehnte.
Mit der Veröffentlichung von Android Studio 3.0 verfügen wir nun endlich über eine Version der Android-Toolchain, die einige der wichtigsten Funktionen von Java 8 unterstützt.
In dieser Serie werde ich Ihnen zeigen, wie Sie eine Unmenge von Boilerplate-Code aus Ihren Projekten entfernen, riesige Datenmengen mühelos verarbeiten und sogar einen funktionaleren Stil in Ihre Java-Programmierung mit Java 8 aufnehmen können Ein tieferer Einblick in die Java 8-Funktionen, die Sie heute verwenden können.
Wenn Sie diese Serie abgeschlossen haben, können Sie alle folgenden Java 8-Funktionen in Ihren Android-Projekten verwenden:
In diesem ersten Beitrag werden wir uns das Feature anschauen, das bei der ersten Veröffentlichung von Java 8 am meisten für Furore sorgte und das Potenzial hat, Android-Entwicklern den größten Unterschied zu machen: Lambda-Ausdrücke.
Bevor Sie mit der Verwendung beginnen können irgendein Java 8-Funktionen müssen Sie sicherstellen, dass Ihre Entwicklungsumgebung für die Unterstützung dieser Java-Version eingerichtet ist.
Wenn Sie Java 8 noch nicht installiert haben, müssen Sie das neueste JDK8 herunterladen und den JDK-Pfad von Android Studio aktualisieren, sodass er auf das JDK8-Paket zeigt:
Wenn Sie nicht sicher sind, welche Version von Java Sie installiert haben, können Sie dies überprüfen, indem Sie ein Terminalfenster (wenn Sie ein Mac-Benutzer sind) oder eine Eingabeaufforderung (unter Windows) öffnen und dann Folgendes ausführen Befehl:
Java-Version
Wenn Build 1.8 oder höher zurückgegeben wird, können Sie loslegen!
Sie müssen außerdem Android Studio 3.0 Preview 1 oder höher installiert haben. Um die Wahrscheinlichkeit von Fehlern und anderen merkwürdigen Verhaltensweisen zu verringern, wird jedoch empfohlen, die neueste Version von Android Studio 3.0 zu installieren. idealerweise eine stabile Version von Android Studio 3.0 (die zum Zeitpunkt des Schreibens noch nicht verfügbar war).
Als Nächstes müssen Sie einige Änderungen an Ihrem Projekt vornehmen build.gradle
Dateien. Normalerweise müssen Sie nur ein paar Zeilen Code hinzufügen, in dem festgelegt wird, dass dieses Projekt Java 8-Bytecode generieren soll. Wenn Sie jedoch zuvor mit dem Jack-Compiler oder dem beliebten Retrolambda-Projekt mit Java 8-Funktionen experimentiert haben, müssen Sie diese Tools deaktivieren, bevor Ihr Projekt die neue und verbesserte Java 8-Unterstützung der Standard-Toolchain von Android verwenden kann.
In den folgenden Abschnitten zeige ich Ihnen, wie Sie die Java 8-Unterstützung aktivieren und gegebenenfalls Retrolambda und Jack deaktivieren.
Vorausgesetzt, Sie haben Jack noch nicht aktiviert oder Retrolambda als Projektabhängigkeit hinzugefügt, ist der erste Schritt das Öffnen Ihrer Projektebene build.gradle
Datei und vergewissern Sie sich, dass Sie Version 3.0.0-alpha1 (oder höher) des Gradle for Android-Plugins verwenden:
buildscript Repositorys google () jcenter () Abhängigkeiten Klassenpfad 'com.android.tools.build:gradle:3.0.0-alpha6'
Als nächstes öffnen Sie jede Modulebene build.gradle
Datei, in der Sie Java 8-Funktionen verwenden möchten, und legen Sie die Sprachebene des Quellcodes fest und die Version des generierten Java-Bytecodes in JavaVersion.VERSION_1_8
:
android compileSdkVersion 26 buildToolsVersion "26.0.1" defaultConfig applicationId "com.jessicathornsby.myapplication" minSdkVersion 26 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "und compileOptions sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
Der Jack-Compiler ist zwar veraltet, aber solange er aktiviert ist, verwendet Ihr Projekt die von Jack bereitgestellte Java 8-Unterstützung und nicht die Unterstützung der Standard-Toolchain von Android.
Die Verwendung eines veralteten Tools ist nie eine gute Idee, aber es gibt einige weitere Gründe, warum Sie vom Jack-Compiler aus migrieren sollten, falls Sie dies nicht bereits getan haben.
Erstens unterstützt Jack möglicherweise eine Teilmenge von Java 8-Funktionen. Im Gegensatz zur Standard-Toolchain werden jedoch keine Bibliotheken von Drittanbietern unterstützt, die diese Funktionen verwenden. Wenn Sie also Jack verwenden, schränken Sie Ihre Optionen bei Bibliotheken von Drittanbietern sofort ein.
Zweitens nimmt der Jack-Compiler Java-Code und konvertiert ihn direkt in dex, ohne einen Zwischenbytecode zu erzeugen. Solange Jack aktiviert ist, können Sie keine der Tools verwenden, die auf diese Zwischenausgabe angewiesen sind, z. B. Anmerkungsprozessoren und Bytecode-Analysatoren.
Um den Jack-Compiler zu deaktivieren, öffnen Sie Ihre Modulebene build.gradle
Datei und entfernen Sie die JackOptions
Abschnitt, aber stellen Sie sicher, dass Sie die compileOptions
Block intakt:
android compileSdkVersion 26 buildToolsVersion "26.0.1" defaultConfig applicationId "com.jessicathornsby.myapplication" minSdkVersion 26 targetSdkVersion 26 versionCode 1 versionName "1.0" // Entfernen Sie den gesamten jackOptions-Abschnitt // jackOptions aktiviert true testInstrumentationRunner ". test.runner.AndroidJUnitRunner "// Entferne nicht den Abschnitt compileOptions // compileOptions sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
Ähnlich wie Jack unterstützt Retrolambda keine Bibliotheken von Drittanbietern, die Java 8-Sprachfunktionen verwenden. Wenn Ihr Projekt für die Verwendung des Retrolambda-Plugins eingerichtet ist, sollten Sie dieses Plugin entfernen, damit Ihr Projekt auf die Standard-Toolchain zurückgesetzt werden kann.
Öffnen Sie Ihre Projektebene build.gradle
Datei und entferne Retrolambda als Projektabhängigkeit:
Abhängigkeiten Klassenpfad 'com.android.tools.build:gradle:3.0.0-beta2' // Entfernen Sie die folgende Zeile // Klassenpfad 'me.tatarka: gradle-retrolambda: 3.7.0'
Entfernen Sie dann das Retrolambda-Plugin von allen Modulebenen build.gradle
Dateien:
plugin anwenden: 'com.android.application' // Die folgende Zeile entfernen // plugin anwenden: 'me.tatarka.retrolambda' android … // Der compileOptions-Block darf nicht gelöscht werden! // compileOptions sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
Der einfachste Weg, um zu überprüfen, ob Ihr Projekt jetzt Java 8 unterstützt, besteht darin, einen schnellen Lambda-Ausdruck zu schreiben und zu prüfen, ob Ihr Projekt noch kompiliert wird.
Fügen Sie Ihrer Benutzeroberfläche eine Schaltfläche hinzu (oder verwenden Sie eine bereits vorhandene Schaltfläche), und implementieren Sie dann eine onClickListener
Verwenden Sie für diese Schaltfläche einen Lambda-Ausdruck. Machen Sie sich keine Sorgen, wenn der folgende Code jetzt keinen Sinn ergibt - er wird am Ende dieses Artikels erscheinen!
import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.Button; Import android.view.View; import android.widget.Toast; public class MainActivity erweitert AppCompatActivity @Override protected void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); // Implementiere den onClickListener mit einem Lambda-Ausdruck // Button button = (Button) findViewById (R.id.button); if (button! = null) button.setOnClickListener ((Ansicht anzeigen) -> Toast.makeText (dies ist "Ich wurde in Java 8 geschrieben!", Toast.LENGTH_LONG) .show ());
Prüfen Sie, ob Ihr Projekt immer noch kompiliert wird Sync aus dem angezeigten Banner oder durch Auswählen Extras> Android> Projekt mit Verlaufsdateien synchronisieren aus der Android Studio-Symbolleiste.
Wenn Android Studio keine Fehler ausgibt, können Sie alle Funktionen verwenden, die zu Beginn dieses Artikels aufgeführt sind, einschließlich Lambda-Ausdrücken!
Lambda-Ausdrücke waren mit Abstand die größte neue Funktion von Java 8 und können eine enorm Auswirkungen auf die Menge an Boilerplate-Code, den Sie schreiben müssen, wenn Sie so ziemlich jede Android-App erstellen.
Im Wesentlichen stellt ein Lambda-Ausdruck eine Funktion dar, die keiner Klasse angehört und die Sie problemlos weitergeben und bei Bedarf ausführen können.
Diese Funktion beseitigt eine langjährige Frustration, die viele Android-Entwickler mit Java erlebt haben: Als objektorientierte Sprache hat das Weitergeben von Codeblöcken stattgefunden immer fühlte sich schwieriger als es sein sollte. Wenn Sie zum Beispiel einen neuen Thread erstellen und dann etwas Code an diesen Thread übergeben möchten, müssen Sie normalerweise einen Thread mit einer anonymen Implementierung der Runnable-Schnittstelle instanziieren. Dies ist eine Menge Arbeit, nur um Code zu übergeben! Durch die einfache Übergabe einer Funktion an eine Methode können Lambda-Ausdrücke einige der häufigsten Aufgaben vereinfachen, die Sie als Android-Entwickler ausführen.
Lambda-Ausdrücke sind auch eine willkommene Ergänzung für alle Java-Entwickler, die ihre Programmierung funktionaler gestalten möchten. Vor Java 8 musste für das Codieren in einem funktionalen Stil zwangsläufig viel Boilerplate-Code geschrieben werden. Da Sie nun Funktionen mit Lambda-Ausdrücken herumgeben können, muss das Schreiben von Java-Code auf weniger objektorientierte Weise nicht erforderlich sein eine Tonne anonyme Kurse schreiben.
Sie erstellen einen Lambda-Ausdruck mit der folgenden Syntax:
(Argument) -> Ausdruckskörper
Der Pfeiloperator ist ziemlich selbsterklärend, aber die Regeln für die Strukturierung von Argument und Ausdruck des Lambdas können variieren, je nachdem, was Sie erreichen wollen. Lassen Sie uns diese beiden Elemente genauer untersuchen.
Das Argument ist ein oder mehrere Parameter fast immer in Klammern eingeschlossen. Auch wenn Ihr Lambda-Ausdruck keine Parameter enthält, müssen Sie immer noch leere Klammern angeben. Beispiel:
() -> System.out.println ("Dieser Lambda-Ausdruck hat keine Parameter");
Die Ausnahme zu dieser Regel ist, wenn Ihre Methode über einen einzelnen Parameter verfügt, dessen Typ abgeleitet wird. In diesem Fall können Sie die Klammern weglassen:
textView.setOnLongClickListener (event -> System.out.println ("Long Click"));
Sie können mehrere Parameter in Ihrem Argument verwenden, indem Sie jeden Parameter durch ein Komma trennen:
(Parameter1, Parameter2) -> System.out.println ("Parameter:" + Parameter1 + "," + Parameter2);
In Lambdas ist eine Typeninferenz möglich, sodass Sie den Datentyp im Allgemeinen aus Ihrem Argument weglassen können. Wenn der Compiler den Datentyp jedoch nicht ableiten kann, müssen Sie den Typ vor Ihren Parametern hinzufügen:
Button button = (Button) findViewById (R.id.button); if (button! = null) button.setOnClickListener ((View view) -> Log.d ("debug", "button clicked"));
Der Ausdruckskörper ist der Code, den Sie ausführen möchten. Dies kann ein einzelner Ausdruck oder mehrere Codezeilen sein. Wenn Sie mehrere Zeilen ausführen möchten, müssen Sie einen Anweisungsblock erstellen, indem Sie diesen Abschnitt Ihres Codes mit geschweiften Klammern umgeben:
Button button = (Button) findViewById (R.id.button); button.setOnClickListener (view -> Log.d ("debug", "Button clicked"); Toast.makeText ("Ich wurde in Java 8 geschrieben!", Toast.LENGTH_LONG) .show ();
Wenn Ihr Ausdruck einen Wert zurückgibt, muss er mit einer return-Anweisung zurückgegeben werden. Beispiel:
(Parameter1) -> System.out.println ("Parameter:" + Parameter1); Rückgabe "Rückgabewert";
Nun haben wir einen Überblick über die verschiedenen Möglichkeiten, wie Sie einen Lambda-Ausdruck strukturieren können. Lassen Sie uns einen Blick auf einige der häufigsten Szenarien werfen, in denen Sie Lambda-Ausdrücke in Ihrer Android-Entwicklungsarbeit verwenden können.
Ihre typische Android-App muss in der Lage sein, auf eine Vielzahl von Benutzereingabeereignissen zu reagieren, und Lambda-Ausdrücke können die Ereignisbehandlung erheblich vereinfachen.
Im folgenden Code verwenden wir eine anonyme Klasse, um eine Instanz von zu erstellen onClickListener
mit einem überschriebenen onClick
Methode. Die Chancen stehen gut, dass Sie diese Art von Code geschrieben haben zahllos mal.
Button button = (Button) findViewById (R.id.button); button.setOnClickListener (new View.OnClickListener () @Override public void onClick (View view) doSomething (););
Durch Umschreiben des obigen Codes mit einem Lambda-Ausdruck können wir Folgendes entfernen:
new View.OnClickListener ()
public void onClick (Ansicht anzeigen)
Ansicht anzeigen
Das bedeutet, dass wir dieselbe Funktionalität mit einer einzigen Zeile implementieren können:
button.setOnClickListener (view -> doSomething ());
Multithreading ist ein weiteres häufiges Szenario, in dem Sie mit Lambda-Ausdrücken saubereren Code schreiben können. Standardmäßig verfügt Android über einen einzigen Benutzeroberflächen-Thread (Benutzeroberfläche), der für die Behandlung aller Benutzerinteraktionen, das Weiterleiten von Ereignissen an die entsprechenden Benutzeroberflächen-Widgets und das Ändern der Benutzeroberfläche verantwortlich ist. Sobald Sie diesen UI-Thread mit lang andauernden oder intensiven Vorgängen blockieren, reagiert Ihre Anwendung möglicherweise nicht mehr und kann sogar den ANR-Dialog (Application Not Responding) von Android auslösen. Das Erstellen zusätzlicher Threads und das Zuweisen von Code zum Ausführen auf diesen Threads ist daher häufig ein wesentlicher Bestandteil der Android-Entwicklung.
Vor Java 8 mussten Sie zum Zuweisen von Code für die Ausführung in einem zusätzlichen Thread eine anonyme Klasse erstellen, die das implementiert Lauffähig
Schnittstelle:
Runable r = new Runable () @Override public void run () System.out.println ("Mein lauffähig"); ; Thread Thread = neuer Thread (r); thread.start ();
Alternativ können Sie einen neuen Thread mit einer anonymen Implementierung des Befehls instanziieren Lauffähig
Schnittstelle:
Thread Thread = Neuer Thread (new Runnable ()) @Override public void run () System.out.println ("My runnable");); thread.start ();
Das Ersetzen dieser anonymen Klasse durch einen Lambda-Ausdruck kann dazu führen, dass diese Aufgabe häufig ausgeführt wird viel prägnanter:
Lauffähig r = () -> System.out.println ("mein lauffähig"); ; // den neuen Thread starten // neuer Thread (r) .start ();
Wenn Sie die Bibliothek RxJava oder RxAndroid verwenden, können Sie schließlich Lambda-Ausdrücke verwenden, um beim Erstellen von Observablen zu helfen.
Hier schaffen wir ein einfaches Beobachtbar
das strahlt die hallo Weltzeichenkette auszu allen seinen Beobachter
:
Observable.just ("Hallo, Welt!") .Subscribe (neue Action1() @Override public void call (Zeichenfolge s) Log.d (TAG, s); );
Wenn Sie einen Lambda-Ausdruck verwenden, können Sie all das ersetzen Aktion1
Code mit einer einzelnen Zeile:
Observable.just ("Hallo, Welt!") .Subscribe (s -> Log.d (TAG, s));
Nachdem wir die Theorie hinter einem neuen Feature gelesen haben, besteht die nächste Herausforderung darin, sich tatsächlich daran zu gewöhnen mit diese neue Funktion. Dies kann besonders bei Lambdas, die anstelle des bekannten Boilerplate-Codes verwendet werden sollen, besonders schwierig sein, da immer die Versuchung besteht, einfach auf das zurückzugreifen, was Sie wissen.
Android Studio verfügt über einige Funktionen, die Ihnen den letzten Anstoß geben können, um vertrauten, aber klobigen Code durch glänzende neue Lambda-Ausdrücke zu ersetzen.
Die erste Funktion ist das Absichtsmenü von Android Studio, mit dem jede kompatible anonyme Klasse automatisch in den entsprechenden Lambda-Ausdruck umgewandelt werden kann. Dies ist perfekt, wenn Sie sich nicht sicher sind, wie Sie einen bestimmten Code in einem Lambda-Format schreiben: Schreiben Sie ihn einfach wie gewohnt und verwenden Sie dann die automatische Konvertierungsfunktion des Intent-Aktionsmenüs.
So konvertieren Sie eine anonyme Klasse automatisch in einen Lambda-Ausdruck:
Alternativ können Sie das Inspection-Tool von Android Studio zum Markieren verwenden jeden anonyme Klasse, die Sie möglicherweise durch einen Lambda-Ausdruck für Ihr gesamtes Projekt ersetzen können. Sie können dann entweder jede anonyme Klasse manuell umschreiben oder die automatische Konvertierungsfunktion von Android Studio anzeigen lassen, wie es gemacht wird.
Um jede anonyme Klasse hervorzuheben, die Android Studio möglicherweise durch einen Lambda-Ausdruck ersetzen könnte:
Das Fenster Prüfergebnisse sollte jetzt angezeigt werden und eine Liste aller anonymen Klassen anzeigen, die Sie durch einen Lambda-Ausdruck ersetzen können. Um einen anonymen Unterricht näher zu betrachten, einfach Doppelklick diese Klasse in der Untersuchungsergebnisse Fenster und Android Studio öffnet die Datei und führt Sie zu der Zeile, in der sich diese anonyme Klasse befindet.
Um die aktuell ausgewählte anonyme Klasse durch einen Lambda-Ausdruck zu ersetzen, geben Sie das ein Durch Lambda ersetzen Knopf ein Klick.
Wenn Android Studio das Fenster mit den Inspektionsergebnissen nicht automatisch öffnet, können Sie es manuell durch Auswahl von starten Ansicht> Werkzeugfenster> Prüfergebnisse aus der Android Studio-Symbolleiste. Wenn Inspektionsergebnisse tut nicht erscheinen in der Werkzeug Windows Untermenü, müssen Sie möglicherweise auswählen Analysieren> Code prüfen… zuerst aus der Android Studio-Symbolleiste.
Trotz der vielen Vorteile, die Lambda-Ausdrücke zu bieten haben, gibt es einen wichtigen Nachteil, den Sie beachten sollten, bevor Sie sie in Ihren Code einfügen. Da Lambdas keinen Namen haben, können Sie sie nicht direkt aus Ihrem Testcode heraus aufrufen. Das Hinzufügen einer großen Anzahl von Lambdas zu Ihrem Projekt kann das Testen erschweren.
Idealerweise sollten Ihre Lambda-Ausdrücke zu einfach sein, um sie zu brechen, daher sollte es nicht zu groß sein, sie nicht zu testen. Wenn Sie jedoch ein Lambda testen müssen, können Sie es immer wie eine private Methode behandeln und den Unit-Test durchführen Ergebnis, anstatt das Lambda selbst. Alternativ können Sie den Lambda-Ausdruck in eine eigene Methode umwandeln, so dass Sie ihn direkt referenzieren und ihn daher als normal testen können.
In diesem ersten Beitrag über Java 8-Sprachfunktionen haben wir untersucht, wie Sie Ihre Android-Projekte zur Unterstützung von Java 8 einrichten und wie Sie Boilerplate-Code reduzieren, indem Sie anonyme Klassen durch Lambda-Ausdrücke ersetzen.
Im nächsten Beitrag werde ich Ihnen zeigen, wie Sie noch mehr Code aus Ihren Android-Projekten schneiden können, indem Sie Lambda-Ausdrücke mit Methodenreferenzen kombinieren und wie Sie Ihre Schnittstellen mit Standard- und statischen Schnittstellenmethoden verbessern können.
In der Zwischenzeit finden Sie einige unserer anderen Beiträge zur Entwicklung von Android-Apps!