Weder findViewById() noch Binding ?!?

Huri57

Cadet 2nd Year
Registriert
Mai 2020
Beiträge
23
Hallo,
ich bin gerade dabei das App-Programmieren mit Kotlin zu lernen. Ich nutze Udacity als Lernplattform; die verwenden leider noch die Android Studio Version von vor einiger Zeit...
mir ist nun folgendes aufgefallen:
Das Binding ersetzt ja FindViewById() und ist deutlich effizienter.

dabei habe ich folgendes festgestellt:
ich habe in meiner XML-Datei ein Button mit der Id „My_button“. Wenn ich nun in meine Kotlin-Datei reingehe und den Button einer variable Zuordnen will, hätte ich ja eigentlich die Möglichkeit mit dem binding oder eben FindViewById (). Ich hab jetzt das binding und meine methode in addNickname () (val mybutton = My_button) genutzt. Hier mein Programmiertes (Nicht 100% vollständig) : Programmiertes.docx

Ich frage mich nun was den diese Methode vom direkten Zuordnen bewirkt; Weil so müsste man eigentlich amwenigsten schreiben.

vielen Dank für die Antworten schon einmal! 😀

[IMG]https://www.computerbase.de/forum/attachments/mainactivity-png.939733/?hash=59cf8de0daeaa1f0f659b84084adfb54[/IMG]
 
Du wirfst hier einiges durcheinander. Mal ein kurzer Überblick über das Thema:

Eine Activity oder Fragment ist vereinfach gesagt ein eigenständiger Screen in deiner App, für den man gewöhnlich ein XML Layout entwirft und beim Start (onCreate) der Activity/dem Fragment zuweist. Dies kann man über setContentView. Diese lädt das Layout, die Layout-Größen der Views werden berechnet und die Views werden auf dem Screen gezeichnet.

Wenn man nun zur Laufzeit (also nach dem Start des Screens), Views verändern oder auf User-Interaktionen reagieren möchte, muss man für Gewöhnlich die Views im Code referenzieren um zB Click-Listener zu setzen.

findViewById():
Dies ist die ursprüngliche Art. Hierbei gibt man die ID der View aus dem XML Layout an. Problem dabei: Der Wert kann zur Laufzeit ein anderer Typ oder sogar null sein, weil der Compiler nicht sicherstellen kann, dass die View existiert. Die Abfrage wird nicht gecached und wenn die View die du ansprechen möchtest verschachtelt liegt, durchläuft die Methode rekursiv alle Views und prüft ob die ID passt. Zudem ist die Schreibweise unübersichtlich.

Daher wird findViewById() praktisch gar nicht mehr verwendet.

Eine Alternative war lange Zeit Butterknife, welches aber inzwischen auch überholt ist und ich daher nicht näher erläutere.

Kommen wir also nun zu den moderneren Arten die Views zu referenzieren:

kotlinx.android.synthetic:
Diese ist eine Funktionalität die über ein Kotlin Plugin verfügbar ist. Diese findet man auch in deinem Code-Auschnitt:
Code:
import kotlinx.android.synthetic.main.activity_main.*
Du nutzt dies für NicknameEdit und NicknameView in der addNickname() Methode.

Vermutlich hast du in deiner build.gradle folgendes Plugin hinzugefügt:
Code:
apply plugin: 'kotlin-android-extensions'

Das Plugin generiert im Hintergrund zusätzliche Dateien die ermöglichen, dass man die IDs aus dem XML Layout direkt im Code referenzieren kann. Diese Lösung besitzt eine Caching Logik, jedoch kann hier auch der Compiler nicht sicherstellen, dass die Views tatsächlich zur Laufzeit verfügbar sind. Daher sollte man diese auch nicht verwenden. Du solltest das Plugin entfernen und dich auf eine Art die Views zu referenzieren beschränken!

View Binding/Data Binding:
Dies sind inzwischen die bevorzugte Variante um Views zu referenzieren, da diese bereits beim Kompilieren sicherstellen, dass alle Views verfügar sind und diese auch effizient gecached werden. Auch hier werden im Hintergrund zusätzliche Dateien generiert. Jedoch stellt das Initialisieren im onCreate sicher, dass genau dieses Layout auch geladen wurde und auch wirklich alle Views verfügbar sind.

View Binding (ist noch recht neu) und Data Binding funktionieren ähnlich. Du hast dich in deinem Beispiel für Data Binding entschieden. Das ist in der Entwickler-Community aber umstritten, da man die Logik zum Zuweisen der Daten und Klick-Events bereits im XML definiert.

Ich persönlich würde dir davon abraten und stattdessen nur das ViewBinding nutzen. Also alle
Code:
<data>
Blöcke aus dem XML entfernen und stattdessen die Werte im Code setzen.

Hier auch noch ein paar Infos zu Data Binding vs View Binding und den Vorteilen zu findViewById.


Zu deiner Frage: Du musst deiner Activity irgendwie mitteilen welches XML Layout sie laden soll. Dies macht man (wie anfangs beschrieben) mittels setContentView. Beim Data Binding übernimmt dies die DataBindingUtil Klasse (wie gesagt, würde das nicht nutzen und dem Beispiel aus dem View Binding folgen). Daher musst du in jedem Fall das onCreate() überladen und erst das Layout setzen.
 
Zuletzt bearbeitet:
@Huri57 : Hier gehts ums Programmieren. Setze Deinen Programmcode in Code-Tags. Irgendwelchen windigen Links zu unbekannten Zielen mit Downloads unbekannten Inhalts für die zu als Tüpfelchen auf dem i auch noch Javascript vorausgesetzt wird zieht sich hier hoffentlich niemand rein.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: Sparta8, bog und G00fY
G00fY schrieb:
Unnötiges Vollzitat durch Moderator entfernt
Vielen vielen Dank für die ausführliche Antwort; habe es relativ gut jetzt verstanden🙂.
G00fY schrieb:
stattdessen die Werte im Code setzen.
Meinst du damit etwa, die ganzen Werte in den Values, wie strings.xml; dimens.xml etc., einzusetzen und dann im Layout XML zu verwenden?
 
Zuletzt bearbeitet von einem Moderator: (Unnötiges Vollzitat durch Moderator entfernt)
Und noch eine Frage (bin relativ neu im Programmier-Geschäft, also bitte nicht wundern, falls diese Frage super dumm ist 😅😅):

Wozu muss denn der Compiler sicherstellen, dass die Views vorhanden sind; wenn man die Views referenziert wird doch schon geguckt ob die Views überhaupt existieren oder etwa nicht?
sorry für diese dumme Frage 😅
Ergänzung ()

Hayda Ministral schrieb:
@Huri57 : Hier gehts ums Programmieren. Setze Deinen Programmcode in Code-Tags. Irgendwelchen windigen Links zu unbekannten Zielen mit Downloads unbekannten Inhalts für die zu als Tüpfelchen auf dem i auch noch Javascript vorausgesetzt wird zieht sich hier hoffentlich niemand rein.
Ich hatte nicht die Programmiersprache Kotlin entdeckt(beim einfügen von Codes), deswegen dachte ich mache ich das einfach so😅😅. Aber du hast recht, so links können ganz schön gefährlich enden😅😅.
Das heißt man klickt einfach auf General Code oder? Bzw wie macht man die Code Tags?
 
Huri57 schrieb:
Meinst du damit etwa, die ganzen Werte in den Values, wie strings.xml; dimens.xml etc., einzusetzen und dann im Layout XML zu verwenden?
Nein, nur die Funktionen von Data Binding solltest du nicht nutzen. Also statt im XML sowas zu schreiben wie
XML:
<TextView android:id="@+id/name_text"
    android:text="@={myName.name}"
    ...
setzt man den Text einfach im Code:
Code:
private lateinit var binding: ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle) {
    super.onCreate(savedInstanceState)
    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView( binding.root)

    binding.nameText.text = myName.name
   ...
So sähe dann dein Kotlin Code aus. Du kannst dann auch in allen anderen Methoden innerhalb der Activity auf das binding Objekt und die darin liegenden Views aus deinem XML Layout (jede braucht eine eindeutige ID) zugreifen.

Huri57 schrieb:
Wozu muss denn der Compiler sicherstellen, dass die Views vorhanden sind; wenn man die Views referenziert wird doch schon geguckt ob die Views überhaupt existieren oder etwa nicht?
Ziel beim Programmieren ist es immer, das möglichst viele Prüfungen und Errorchecks vom Compiler übernommen werden. Spricht es ist immer besser, wenn ein Programmcode sich aufgrund eines Fehlers gar nicht bauen lässt, anstatt dass deine Programm zur Laufzeit (im schlimmsten Fall des Endnutzers) abstürzt.

Besonders Typensicherheit (also ob die View hinter einer bestimmten ID wirklich eine TextView und keine ImageView ist zB) kann der Compiler ja theoretisch ganz einfach sicherstellen. Dadurch das aber zB mit findViewById() das Ergebnis erst zu Laufzeit vorliegt, kann der Compiler hier nichts im Voraus prüfen. Bei kotlinx.android.synthetic besteht das Problem, dass du praktisch jede View aus einem beliebigen Screen im Programmcode importieren kannst, die aber zur Laufzeit überhaupt nicht beim Start des Screens mittels setContentView() geladen wird. Also auch hier kann der Compiler dir keine Sicherheit geben, dass zur Laufzeit alles da ist.

Genau dieses Problem löst eben View Binding (welches erst mit Android Studio 3.6/im Februar diesen Jahres) vorgestellt wurde. Hier hat man eben genau die View-Instanzen, mit denen die View auch tatsächlich geladen wird. Ich vermute die meisten Tutorials sind bei dem Thema inzwischen recht veraltet. ;)
 
Zuletzt bearbeitet:
Ah vielen Dank (wirklich super Erklärungen; versteh sie direkt beim ersten mal lesen;))!
Ich werde mal Udacity anschreiben...
Vielleicht werden die Videos ja bald geupdated ;). Solange wird sicher Youtube noch etwas helfen.
 
Zurück
Oben