Les expressions lambda Java (Kotlin / JVM) ne sont pas toujours des instances séparées

Lors de l'écriture d'une expression lambda au lieu de la classe interne anonyme de Java, j'ai supposé que ce serait une instance distincte, et c'est un mémo qui est devenu un problème dans la gestion de chaque instance.

Afin de réaliser que l'utilisation de LiveData des composants d'architecture Android pour fournir une source de données gérée par un LiveData comme un autre LiveData, l'implémentation suivante transmet un Observer vide à LiveData.observer. J'en étais accro.

Exemple de code

kotlin


//Contre les LiveData qui s'incrémentent toutes les secondes uniquement lors de l'observation
class Counter : LiveData<Int>() {
    private var timer: Timer? = null

    //LiveData qui ne fournit que des nombres pairs tout en s'appuyant sur des compteurs de classe externes
    var oddCounter: MutableLiveData<Int> = object : MutableLiveData<Int>() {
        override fun observe(owner: LifecycleOwner, observer: Observer<Int>) {
            super.observe(owner, observer)

            //Parce qu'il y a un compteur dans la classe externe
            //En observant cela aussi, activez-le et démarrez le compteur.
            [email protected](owner, Observer<Int> { })
        }
    }

    override fun onActive() {
        val task = object : TimerTask() {
            override fun run() {
                var nextCount = (value ?: 0) + 1

                postValue(nextCount)
                if (nextCount % 2 != 0) {
                    oddCounter.postValue(nextCount)
                }
            }
        }
        timer = Timer()
        timer?.scheduleAtFixedRate(task, 0, 1000)
    }

    override fun onInactive() {
        timer?.cancel()
    }
}

class MainKotlinActivity : AppCompatActivity() {
    private val counter = Counter()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        //Code que les activités et les processus observent dans un exemple d'implémentation observé par plusieurs propriétaires
        counter.oddCounter.observe(this, Observer<Int> { value ->
            value?.let { println("activity got $it") }
        })
        counter.oddCounter.observe(ProcessLifecycleOwner.get(), Observer<Int> { value ->
            value?.let { println("process got $it") }
        })
    }
}

Quand je fais cela, le code [email protected] (owner, Observer <Int> {}) est appelé deux fois pour différentes instances de ʻowner, mais la deuxième fois java.lang.IllegalArgumentException J'obtiens l'exception: impossible d'ajouter le même observateur avec des cycles de vie différents.

La cause est la suivante.

--ʻObserver {} `retourne la même instance (dans la même classe) quel que soit le nombre de fois qu'elle est exécutée

Probablement, ʻObserver {} ʻest en train de détourner une instance parce que la fermeture ne dépend pas de la portée de l'appelant et est fixe. En fait, si ʻObserver {} ʻest ʻObserver {print (owner.toString ())} , c'est-à-dire que l'implémentation dépend du ʻowner qui change à chaque appel, c'est différent. A renvoyé une instance.

En premier lieu, je pensais que le code d'octet serait complètement différent entre la classe interne anonyme et l'expression lambda, donc http://www.ne.jp/asahi/hishidama/home/tech/java/lambda.html#h_invokedynamic Lire ceci Hmmmm.


Cette fois, j'ai écrit ʻObserver {} `pour créer une implémentation vide de l'instance Observer, mais il y a un arrière-plan que cela s'est produit lorsque j'ai suivi l'avertissement émis par l'EDI. En fait, il peut s'écrire de plusieurs manières comme suit. ..

La manière la plus orthodoxe: la classe interne anonyme de Java.

java


Observer<Integer> nullObserver = new Observer<Integer>() {
    @Override
    public void onChanged(@Nullable Integer integer) {
    }
};
observe(owner, nullObserver);

Mais cela est suggéré à Android Studio car "peut être remplacé par lambda", ce qui se traduit par du code utilisant des expressions lambda comme suit:

java


Observer<Integer> nullObserver = value -> {};
observe(owner, nullObserver);

La même chose est vraie pour Kotlin.

kotlin


val nullObserver = object : Observer<Int> {
    override fun onChanged(t: Int?) {
    }
}
observe(owner, nullObserver);

kotlin


val nullObserver = Observer<Int> { }
observe(owner, nullObserver);

J'ai de nouveau réalisé que je devais être conscient des différences entre eux et les utiliser correctement.

Si vous laissez simplement la classe interne anonyme d'origine ou l'expression d'objet, une autre personne peut effectuer à nouveau la même modification selon la suggestion de l'EDI, donc instanciez une classe dédiée comme suit: Je l'ai fait.

kotlin


private class NullObserver<T> : Observer<T> {
    override fun onChanged(t: T?) {
    }
}

observe(owner, NullObserver<Int>())

En compilant maintenant l'article de qiita, je me suis demandé s'il aurait été correct de compléter quelque chose avec des commentaires de code source.

fin.


En passant, avec l'exemple de code écrit ici, si vous utilisez Transformations, vous n'aurez pas à faire une observation du ciel aussi compliquée. Cependant, le code réel peut être un peu plus compliqué.

Recommended Posts

Les expressions lambda Java (Kotlin / JVM) ne sont pas toujours des instances séparées
Comprendre les expressions lambda Java 8
À propos des expressions Java lambda
Expliquer les expressions lambda Java 8
[Java] Introduction à l'expression lambda
[Introduction à Java] À propos des expressions lambda
L'origine des expressions Java lambda
Comment utiliser les expressions Java lambda
J'ai essayé de résumer les expressions Java lambda
De nos jours, les expressions Java Lambda et l'API de flux
Organisez la différence de confort d'écriture entre l'expression lambda Java et l'expression lambda Kotlin.