Tauchen Sie in Jetpack Compose

Hallo an alle. Bevor wir uns auf den Weg zum Wochenende machen, teilen wir Ihnen gerne eine weitere Übersetzung mit, die speziell für Schüler des Android-Entwicklers erstellt wurde. Fortgeschrittenenkurs .



Versuch eines neuen UI-Frameworks für Android-Anwendungen


In den letzten Jahren musste ich bei vielen mobilen Projekten verschiedene Technologien wie Android, ReactNative und Flutter einsetzen. Der Wechsel von ReactNative zurück zu klassischem Android hat mich gemischt gemacht. Die Rückkehr nach Kotlin verlief gut, aber ich habe das React UI-Framework wirklich vermisst. Die kleinen wiederverwendbaren Komponenten, aus denen die Benutzeroberfläche besteht, sind großartig und bieten mehr Flexibilität und Entwicklungsgeschwindigkeit.

Zurück im klassischen Android musste ich mir Sorgen machen, dass die Ansichtshierarchie so einheitlich wie möglich bleibt. Aus diesem Grund ist es schwierig, sich wirklich dem Komponentenansatz zu widmen. Dies macht das Kopieren und Einfügen attraktiver, was zu komplexerem und weniger unterstütztem Code führt. Letztendlich halten wir uns davon ab, mit einer Benutzeroberfläche zu experimentieren, die UX verbessern könnte.


Android enthüllt Jetpack Compose. Abbildung: Emanuel Bagilla

Jetpack Komponieren Sie zur Rettung


Nachdem ich mir die Neuigkeiten in Android von der Google I / O 2019-Konferenz angesehen hatte, begann ich sofort mit Compose und versuchte, mehr darüber zu erfahren. Compose ist ein reaktives Toolkit für die Benutzeroberfläche, das vollständig von Kotlin entwickelt wurde. Compose sieht vorhandenen Benutzeroberflächen-Frameworks wie React, Litho oder Flutter sehr ähnlich.

Die derzeitige Struktur des Android-UI-Frameworks besteht seit 2008 und ist im Laufe der Zeit komplexer geworden. Die Wartung ist recht schwierig. Jetpack Compose zielt darauf ab, von vorne zu beginnen und dabei die Philosophie moderner Komponenten zu berücksichtigen. Das Framework wurde mit den folgenden Hauptzielen geschrieben:

  • Inkonsistenz mit Plattformversionen: Auf diese Weise können Sie Fehler schnell beheben, da Compose nicht von neuen Android-Versionen abhängig ist.
  • Kleinerer Technologie-Stack: Das Framework erzwingt nicht die Verwendung von Ansicht oder Fragment beim Erstellen einer Benutzeroberfläche. Alle Elemente sind Komponenten und können frei zusammengesetzt werden.
  • Transparente Statusverwaltung und Ereignisbehandlung: Eines der wichtigsten und komplexesten Dinge, die Sie in großen Anwendungen lösen müssen, ist die Verarbeitung von Datenfluss und Status in Ihrer Benutzeroberfläche. Compose verdeutlicht, wer für den Status verantwortlich ist und wie Ereignisse behandelt werden sollen, ähnlich wie React damit umgeht.
  • Weniger Code schreiben : Das Schreiben einer Benutzeroberfläche in Android erfordert normalerweise viel Code, insbesondere beim Erstellen komplexerer Layouts, z. B. mit RecyclerView. Mit Compose soll die Erstellung einer Benutzeroberfläche erheblich vereinfacht werden.

Dies erleichtert das Erstellen isolierter und wiederverwendbarer Komponenten und das Erstellen eines neuen Bildschirms mit vorhandenen Elementen. Damit Sie sich als Entwickler darauf konzentrieren können, eine praktische Benutzeroberfläche zu erstellen, anstatt zu versuchen, die Ansichtshierarchie zu steuern und Ansicht und Fragment zu zähmen.

Eine einfache Anwendung mit Compose: Hello World


Schauen wir uns den Code für eine einfache Hello World-Anwendung mit Jetpack Compose an.

class ComposeActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { CraneWrapper { MyApp() } } } @Composable fun MyApp() { MaterialTheme { Text(text = "Hello world!", style = +themeTextStyle { h3 }) } } } 

In der onCreate Methode legen wir den Inhalt unserer Anwendung fest, indem wir setContent aufrufen. Dies ist eine Methode, die einen zusammengesetzten Widget-Baum initialisiert und in ein FrameLayout .

Damit es funktioniert, müssen wir unsere Anwendung in CraneWrapper und MaterialTheme CraneWrapper . CraneWrapper ist für die Konfiguration der Anbieter für Context , FocusManager und TextInputService . MaterialTheme benötigt, um die Farben, Stile und Schriftarten Ihrer Widgets bereitzustellen. In diesem Sinne können wir die Text hinzufügen, die unseren Text in einem bestimmten Stil auf dem Bildschirm anzeigt.

Staatliche Einführung


Das Verwalten von Datenflüssen und -zuständen kann eine entmutigende Aufgabe sein. Um zu veranschaulichen, wie einfach es mit Compose ist, erstellen wir eine einfache Zähleranwendung.
Um mit Zuständen zu arbeiten, verwendet Jetpack Compose die Ideen anderer moderner UI-Frameworks wie Flutter und React. Es gibt einen unidirektionalen und reaktiven Datenstrom, der bewirkt, dass Ihr Widget aktualisiert oder neu erstellt wird.

 @Composable fun MyApp() { MaterialTheme { Counter() } } @Composable fun Counter() { val amount = +state { 0 } Column { Text(text = "Counter demo") Button(text = "Add", onClick = { amount.value++ }) Button(text = "Subtract", onClick = { amount.value-- }) Text(text = "Clicks: ${amount.value}") } } 


Im obigen Beispiel fügen wir die Schaltflächen "Hinzufügen" und "Subtrahieren" zusammen mit einer Beschriftung hinzu, die die aktuelle Anzahl der Klicks anzeigt. Wie Sie im folgenden Beispiel sehen können, werden Widgets beim Aktualisieren des Status "Betrag" intelligent neu angeordnet, wenn sich der Status ändert.


Starten Sie eine Demo-Anwendung

Der amount wird mit +state { 0 } initialisiert. Als ich versuchte herauszufinden, was für eine Art Hexerei ist, kroch ich in den Quellcode. Dies ist meine Meinung, obwohl ich immer noch nicht sicher bin, ob ich alles vollständig verstehe.

state {...} erzeugt einen Effect< State < T < code>> . Die Effect Klasse ist eine Fuzzy-Klasse, die einen Block ausführbaren Codes enthält, der im Kontext einer Komposition positionell ausgeführt wird. Die State Klasse enthält einen Wert mit dem Model , wodurch dieser Wert im Wesentlichen beobachtbar wird. Der Operator + ist ein temporärer Operator, der den Status aus dem Effect auflöst.

Benutzerdefinierte Zustandsmodelle


Anstatt +state {} zum Erstellen eines Einzelwertmodells zu verwenden, können wir auch ein benutzerdefiniertes Modell mithilfe der Annotation @Model erstellen. Wir können unsere Zähleranwendung verbessern, indem wir sie in kleinere Widgets aufteilen und das Modell an andere Widgets übergeben, die aktualisiert werden und den Status dieses Modells anzeigen.

 @Model class CounterModel { var counter: Int = 0 var header = "Counter demo" fun add() { counter++ } fun subtract() { counter-- } } 


Mithilfe der Annotation @Model macht das Compose Compiler-Plugin alle Variablen in Ihrem Modell @Model , sodass sie zum Neuanordnen von Widgets verwendet werden können. Aktualisieren wir unser Widget, um CounterModel zu verwenden:

 @Composable fun Counter(counterModel: CounterModel) { Column { CounterHeader(counterModel) AddSubtractButtons(counterModel) CounterLabel(counterModel) } } @Composable fun CounterHeader(counterModel: CounterModel) { Text(text = counterModel.header) } @Composable fun AddSubtractButtons(counterModel: CounterModel) { Button( text = "Add", onClick = { counterModel.add() }) Button( text = "Subtract", onClick = { counterModel.subtract() }) } @Composable fun CounterLabel(counterModel: CounterModel) { Text(text = "Clicks: ${counterModel.counter}") } 


Das einzige Widget, aus dem die Spinner-Anwendung besteht, ist jetzt in mehrere kleinere zusammensetzbare Widgets aufgeteilt. CounterModel wird an verschiedene Widgets übergeben, um entweder den Status des Modells anzuzeigen oder den Status des Modells mithilfe der Funktionen add() oder subtract() zu ändern.

Keine Ansicht mehr


Es ist wichtig zu verstehen, dass Jetpack Compose-Widgets keine Ansicht oder Fragmentierung unter der Haube verwenden. Dies sind nur die Funktionen, die auf der Leinwand gezeichnet werden. Das Compose Compiler-Plugin verarbeitet alle Funktionen mit der Annotation @Composable und aktualisiert automatisch die UI-Hierarchie.

Ein Divider Widget besteht beispielsweise aus einem Padding Widget, das ein DrawFillRect Widget enthält. Wenn man sich den Quellcode von DrawFillRect , wird klar, dass er Linien direkt auf die Leinwand zeichnet. Alle anderen Widgets werden auf die gleiche Weise implementiert.

 @Composable private fun DrawFillRect(brush: Brush) { Draw { canvas, parentSize -> val paint = Paint() brush.applyBrush(paint) canvas.drawRect(parentSize.toRect(), paint) } } 


Der Quellcode für DrawFillRect, der im Divider-Widget verwendet wird.
Wenn wir uns den Layout-Inspektor ansehen, indem wir eine der Beispielanwendungen von Google starten, werden wir deutlich sehen, dass beim Starten der Android-Anwendung mit Compose keine View oder ViewGroups . Wir sehen ein FrameLayout mit dem CraneWrapper , den wir im Code erstellt haben. Von dort aus wird die Hierarchie der Compose-Benutzeroberfläche auf dem Bildschirm angezeigt.


Der Layout Inspector überprüft Jetpack Compose.

Das Fehlen von Ansichten bedeutet auch, dass Jetpack Compose derzeit verfügbare Ansichten wie android.widget.Button nicht verwenden kann und alle Widgets von Grund auf neu erstellen muss. Wenn Sie sich zum Beispiel Flutter ansehen, das denselben Ansatz verwendet, können Sie sehen, dass dies harte Arbeit ist. Dies ist einer der Gründe, warum Jetpack Compose einige Zeit benötigt, bevor es für die Produktion bereit ist.

Alle Elemente sind Widgets.


Genau wie bei Flutter sind bei Compose alle Elemente Widgets. Komplexere Widgets wurden in elementare Widgets mit klaren Verantwortlichkeiten zerlegt. Daher sind auch Polster, Abstandshalter usw. Widgets. Wenn Sie beispielsweise eine Einrückung um eine Schaltfläche hinzufügen möchten, wickeln Sie sie einfach in das Füll-Widget ein:

 Padding(padding = 16.dp) { Button(text = "Say hello", onClick = { ... }) } 


Code mit der Benutzeroberfläche verbinden


Das Kombinieren von Kotlin-Code mit UI-Widgets ist sehr einfach. Zum Beispiel, wenn Sie eine Benutzeroberfläche anzeigen möchten, die sich wiederholt oder von bestimmten Bedingungen abhängt. So können Sie einfach eine Liste von Namen anzeigen, wie unten gezeigt.

 Column { listOf("John", "Julia", "Alice", "Mark").forEach { Text(text = it) } } 


Dies ist eine wirklich leistungsstarke Funktion, aber Sie müssen darauf achten, nicht zu viel Logik auf der Ebene der Benutzeroberfläche zu programmieren.

Kompatibel mit Ihren Android Apps


Compose ist so konzipiert, dass Sie es einer vorhandenen Anwendung hinzufügen und einige Teile Ihrer Benutzeroberfläche schrittweise auf ein neues Framework übertragen können. In den obigen Beispielen wird die Jetpack Compose-Benutzeroberfläche zu einer Aktivität hinzugefügt. Sie können Compose-Widgets auch mithilfe der GenerateView Annotation in ein vorhandenes XML-Layout einbetten:

 @Composable @GenerateView fun Greeting(name: String) { /* … */ } //  -  layout.xml <GreetingView app:name=”John” /> 

Fazit


Ich bin begeistert von Compose, weil es das wachsende Leid verringert, das ich bei der Entwicklung für Android erlebe. Es hilft, flexibler zu sein, sich auf die Erstellung einer praktischen Benutzeroberfläche zu konzentrieren, und klare Verantwortung hilft auch, Fehler zu vermeiden.

Compose hat noch einen langen Weg vor sich, meiner Meinung nach kann es frühestens in ein oder zwei Jahren in der Produktion eingesetzt werden. Ich denke jedoch, dass dies ein guter Zeitpunkt ist, um sich das Jetpack Compose anzusehen. Die Ersteller suchen aktiv nach Feedback. In dieser Phase können Sie noch Änderungen vornehmen. Alle Überprüfungen werden dazu beitragen, dieses neue Framework zu verbessern.

Lesen Sie meinen heutigen Artikel Try Jetpack Compose , um zu erfahren, wie Sie Compose Pre-Alpha anschließen. Ich denke auch, dass es für Sie sehr interessant sein wird, ein Video über deklarative Schnittstellenvorlagen mit Google I / O anzusehen.
Ich freue mich darauf, wenn ich Compose in echten Android-Anwendungen verwenden kann!

Das ist alles. Wir freuen uns auf Ihre Kommentare und haben ein schönes Wochenende!

Source: https://habr.com/ru/post/de458106/


All Articles