Kotlin synthetisch in Adapter oder ViewHolder

84

Ich bin neu in Kotlin. Ich habe findViewByIdin meiner ActivityKlasse eine synthetische Methode anstelle einer nervigen Methode gefunden und versucht, sie zu verwenden , aber ich habe festgestellt: "Wenn wir die synthetischen Eigenschaften in View aufrufen möchten (nützlich in Adapterklassen), sollten wir auch kotlinx.android.synthetic.main importieren .Aussicht.*." Aber ich kann nicht herausfinden, wie es genau funktioniert? Gibt es Beispiele?

Busylee
quelle
Sie können diesen Blog oder dieses Beispiel
Cabezas

Antworten:

96

Einfaches Beispiel von https://github.com/antoniolg/Kotlin-for-Android-Developers

import kotlinx.android.synthetic.item_forecast.view.*

class ForecastListAdapter() : RecyclerView.Adapter<ForecastListAdapter.ViewHolder>() {

    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {

        fun bindForecast(forecast: Forecast) {
            itemView.date.text = forecast.date.toDateString()
        }
    }
}

Keine Notwendigkeit zu schreiben

val view = itemView.findViewById(R.id.date) as TextView
view.text = forecast.date.toDateString()

Gerade

itemView.date.text = forecast.date.toDateString()

Einfach und effektiv!

Peter Zhao
quelle
4
ok, das mag eine dumme Frage sein, aber woher kommt die 'itemView'-Referenz?
Saulo Aguiar
4
Es gibt keinen Cache für Ansichtserweiterungen, daher sollten Verweise auf Ansichten wie in einem normalen viewHolder zwischengespeichert werden.
Miha_x64
20
Leider ruft das auf, um ViewById bei jedem bind () -Aufruf zu finden
Miguel Beltran
2
@Mike seit Kotlin 1.1.4 werden alle Ansichten zwischengespeichert. Auch in ViewHolders. Der Artikel, den Sie gepostet haben, erwähnt dies ebenfalls.
Stefan Medack
2
@StefanMedack Ich bin der Autor des Artikels :) Obwohl ich darauf hinweisen muss, dass es nur ein Teil der experimentellen Funktionen ist und manuell aktiviert werden muss. Ich habe es noch nicht versucht.
Miguel Beltran
37

Kotling 1.1.4 raus

Weitere Informationen: https://antonioleiva.com/kotlin-android-extensions/

Sie müssen Kotlin Android Extentions aktivieren, indem Sie dies zu Ihrem build.gradle hinzufügen:

apply plugin: 'org.jetbrains.kotlin.android.extensions'
androidExtensions {
    experimental = true
}

Seit dieser neuen Version von Kotlin haben die Android-Erweiterungen einige neue interessante Funktionen integriert: Caches in jeder Klasse (die interessanterweise ViewHolder enthält)

Verwenden in einem ViewHolder (oder einer benutzerdefinierten Klasse). Beachten Sie, dass diese Klasse die LayoutContainerSchnittstelle implementieren sollte :

class ViewHolder(override val containerView: View) : RecyclerView.ViewHolder(containerView), 
        LayoutContainer {

    fun bind(title: String) {
        itemTitle.text = "Hello Kotlin!"
    }
}
Dhaval Jivani
quelle
3
Hinzufügen zu diesen Informationen: Gemäß Kotlin 1.1.4 ist die Funktion experimentell und muss in der Datei build.gradle aktiviert werden
Miguel Beltran
2
Ist das nicht mehr experimentell? Ich möchte dies im Produktionscode verwenden
Carson Holzheimer
@CarsonHolzheimer diese Funktion ist noch experimentell
the_dani
anscheinend funktioniert es nicht einmal mit 1.3.21. Ich denke, sie werden es nicht implementieren
user924
aber wir können verwenden containerView.itemTitle.text = "Hello Kotlin!"und ich denke, es ist genug
user924
11

Du brauchst

import kotlinx.android.synthetic.row_wall.view.*

Und später etwas in der Art von:

convertView.titleText.text = item.title

Der Punkt ist, dass die Ansicht. * Erweiterungen in die View-Klasse einführt.

Zsolt Szatmari
quelle
1
Die Antwort wurde bereits gegeben. stackoverflow.com/a/33428208/7767664 warum hast du sie wiederholt?
user924
8

Versuchen

class CustomViewModel(val baseView: View) {
    val firstName = baseView.firstName
    val lastName = baseView.lastName
}

Das Ansichtsobjekt macht die Ansichten verfügbar unter: https://discuss.kotlinlang.org/t/unable-to-use-kotlin-android-extension-in-adapter-class/2890

Hyäne
quelle
Die Antwort wurde bereits gegeben. stackoverflow.com/a/33428208/7767664 warum hast du sie wiederholt?
user924
@ user924. Wenn die Antwort bereits in einem anderen Thread ist, moderieren und markieren Sie den aktuellen Thread als Duplikat und fügen Sie einen Verweis auf einen anderen Thread hinzu
Hyäne
4

Wenn Sie die neueste Version verwenden, müssen Sie nicht experimentell = true hinzufügen.

in Projektebene Gradle

classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.21'

Und auf App-Ebene Gradle

apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions' //These should be on the top of file.

und in Abhängigkeiten ..

implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.21'

und unten importieren als

import kotlinx.android.synthetic.main.your_layout_file_name.view.*

und Beispiel

import kotlinx.android.synthetic.main.item_animal.view.*

class AnimalVH(parent: ViewGroup, layoutID: Int) : BaseViewHolder<Animal>(parent, layoutID) {

    override fun bindData(animal: Animal) {
        itemView.tv_animal.text = animal.title
    }
}

wo BaseViewHolder ist

abstract class BaseViewHolder<T>(parent: ViewGroup, layoutID: Int) : RecyclerView.ViewHolder(
    LayoutInflater.from(parent.context).inflate(layoutID, parent, false)
) {
    abstract fun bindData(model: T)
}
AndroidGeek
quelle
Gibt es eine offizielle Bestätigung dazu? Ich glaube, die Verwendung von .view.*Import besiegt den Zweck, der Fallback wird findViewById<>jedes Mal sein - genau das Muster ViewHolder, von dem man abhält.
Skynet
Erklärt unter: proandroiddev.com/…
Skynet
1

Dies bedeutet, dass Sie diese Zeile am Anfang Ihrer Quelldatei einfügen müssen:

import kotlinx.android.synthetic.main.view.*

Also würden Sie jetzt statt zum Beispiel findView(R.id.textView) as TextViewnur schreiben textView. Letzteres ist eine synthetische Erweiterungseigenschaft, die sich im Paket kotlinx.android.synthetic.main.viewbefindet. Deshalb müssen Sie alles daraus importieren.

Auf der offiziellen Website gibt es ein Tutorial .

Alexander Udalov
quelle
1
Ich habe es schon gesehen. Ich habe es für meine Aktivität getan, wie ich oben beschrieben habe. Aber wie kann ich es in BaseAdapter-Derivaten verwenden?
Busylee
1
Grundsätzlich können Sie die findViewById()Methode für a Viewwie aufrufen holder.findViewById(R.id.name). Mit Kotlin Android Extensions können Sie einfach schreiben holder.name. Angenommen, dieser Code ist in eine getView()Funktion geschrieben:val base = inflater.inflate(R.layout.list_item, parent, false) base.name.text = "John Smith"
Yanex
Was aber, wenn ich mehrere Ansichtshalter mit unterschiedlichen Layouts verwenden muss? Wie kann ich es mit synthetischen realisieren? Weil wir für jedes Layout einen spezifischen "synthetischen Link" verwenden müssen und ich mehrere Layouts mit ähnlichen IDs habe.
Natan Rubinstein
0

Zu Ihrer Information: Für die Ansichtssuche wird eine Datenbindung gegenüber einer synthetischen empfohlen.

Kommentar von einem DA für Android von Google auf Reddit

Hallo! Entwickleranwalt für Android bei Google hier!

Ich wollte hier ein bisschen Hintergrund hinzufügen. Kotlin-Erweiterungen mit synthetischen Ansichten wurden nie absichtlich "empfohlen", obwohl dies nicht als Empfehlung verstanden werden sollte, sie nicht zu verwenden. Wenn sie für Sie arbeiten, können Sie sie weiterhin in Ihrer App verwenden!

Wir haben uns von ihnen entfernt (z. B. unterrichten wir sie nicht im Udacity-Kurs), weil sie einen globalen Namespace von IDs verfügbar machen, der nicht mit dem Layout zusammenhängt, das tatsächlich aufgeblasen ist, ohne dass gegen ungültige Suchvorgänge geprüft wird, sondern nur Kotlin und Don Die Nullfähigkeit wird nicht angezeigt, wenn Ansichten nur in einer bestimmten Konfiguration vorhanden sind. Insgesamt führen diese Probleme dazu, dass die API die Anzahl der Abstürze für Android-Apps erhöht.

Auf der anderen Seite bieten sie eine kompakte API, die die Suche nach Ansichten vereinfachen kann. In diesem Bereich lohnt es sich auch, einen Blick auf die Datenbindung zu werfen, die auch automatische Ansichtssuchen durchführt und in LiveData integriert ist, um Ihre Ansichten automatisch zu aktualisieren, wenn sich Daten ändern.

Heute gibt es in diesem Bereich einige Optionen, die funktionieren:

Die Datenbindung ist die Empfehlung für die Ansichtssuche und -bindung, erhöht jedoch im Vergleich zu Android Kotlin Extensions den Aufwand. Es lohnt sich, einen Blick darauf zu werfen, ob dies gut zu Ihrer App passt. Mit der Datenbindung können Sie auch LiveData beobachten, um Ansichten automatisch zu binden, wenn sich Daten ändern. Im Vergleich zu Kotlin-Erweiterungen wird die Überprüfung der Kompilierungszeit von Ansichtssuchen und Typensicherheit hinzugefügt. Android Kotlin Extensions wird nicht offiziell empfohlen (was nicht mit der Empfehlung gegen identisch ist). Es kommt mit den oben genannten Problemen, so dass wir sie für unseren Code nicht verwenden. Butter Knife ist eine weitere äußerst beliebte Lösung, die sowohl für Kotlin als auch für die Java-Programmiersprache funktioniert. Lesen Sie die Kommentare hier dort durch ' Viele Entwickler, die viel Glück mit Kotlin Extensions haben. Das ist großartig - und etwas, das wir berücksichtigen werden, wenn wir nach Möglichkeiten suchen, unsere APIs weiter zu verbessern. Wenn Sie sich Data Binding noch nicht angesehen haben, probieren Sie es auf jeden Fall aus.

Abgesehen davon ist unser interner Code-Styleguide nicht dazu gedacht, direkt außerhalb unserer Codebasis angewendet zu werden. Zum Beispiel verwenden wir mPrefixVariables, aber es gibt keinen Grund, warum jede App diesem Stil folgen sollte.

user158
quelle