Как правильно отслеживать живые данные с несколькими наблюдениями в Android?

У меня есть действие, и оно обратится к фрагменту-A, а затем к фрагменту-B, как показано ниже.

Activity -> Fragment-A -> Fragment-B

ситуация 1

Эти два фрагмента наблюдают одни и те же LiveData для отображения закусок, как показано ниже.

viewModel.responseData.observe(this, Observer {
            it.getContentIfNotHandled()?.let {
            showSnackBar(it)
}

livedata в viewModel:

var responseData = MutableLiveData<Event<String>>()
responseData.value = Event("$message")

Ошибка: когда я использую приведенный выше код. Он показывает только snackBar в фрагменте-A. фрагмент-B не может получить значение.

ситуация 2

Когда я изменяю код на следующий

viewModel.responseData.observe(this, Observer {
            showSnackBar(it.peekContent())
})

Оба фрагмента могут получить значение.

Ошибка:

После закройте фрагмент и снова поверните. Он показывает закуску, потому что значение responseData все еще существует. Но я не отправил сообщение.

Ссылка на класс Event от Google выглядит следующим образом:

/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package bbin.mobile.ballbet.support

import androidx.lifecycle.Observer
import timber.log.Timber

/**
 * Used as a wrapper for data that is exposed via a LiveData that represents an event.
 */
open class Event<out T>(private val content: T) {

    var hasBeenHandled = false
        private set // Allow external read but not write

    /**
     * Returns the content and prevents its use again.
     */
    fun getContentIfNotHandled(): T? {
        return if (hasBeenHandled) {
            null
        } else {
            hasBeenHandled = true
            content
        }
    }

    /**
     * Returns the content, even if it's already been handled.
     */
    fun peekContent(): T = content
}

/**
 * An [Observer] for [Event]s, simplifying the pattern of checking if the [Event]'s content has
 * already been handled.
 *
 * [onEventUnhandledContent] is *only* called if the [Event]'s contents has not been handled.
 */
class EventObserver<T>(private val onEventUnhandledContent: (T) -> Unit) : Observer<Event<T>> {
    override fun onChanged(event: Event<T>?) {
        event?.getContentIfNotHandled()?.let {
            onEventUnhandledContent(it)
        }
    }
}

Я хочу, чтобы фрагмент отображал для них правильное сообщение SnackBar.

Как правильно соблюдать livedata для нескольких фрагментов в Android?

Заранее спасибо.


person Wun    schedule 24.09.2019    source источник
comment
Пройдите через этот блог, вы узнаете. blog.mindorks.com/   -  person Rajnish suryavanshi    schedule 24.09.2019
comment
пожалуйста, опубликуйте код инициализации viewmodel   -  person Sarah Maher    schedule 24.09.2019
comment
Событие используется для уведомления только для одного значения времени, поэтому, когда вы снова вернетесь к тому же фрагменту, оно не будет снова получать уведомление с тем же значением, если новое событие не будет добавлено в livedata.   -  person Jeel Vankhede    schedule 24.09.2019
comment
@JeelVankhede при использовании peekContent так и будет.   -  person Wun    schedule 24.09.2019
comment
Пожалуйста, покажите класс Event   -  person Arka Prava Basu    schedule 24.09.2019
comment
@ArkaPravaBasu Я добавил   -  person Wun    schedule 24.09.2019


Ответы (1)


Вы правильно наблюдаете LiveData, так устроен класс Event.

Когда вы делаете

viewModel.responseData.observe(this, Observer {
            it.getContentIfNotHandled()?.let {
            showSnackBar(it)
}

getContentIfNotHandled будет возвращать содержимое только один раз, пока не будет снова установлено новое значение. Если FragmentA потребляет это первое FragmentB, не сможет использовать то же значение. Это причина, по которой peekContent работает, поскольку она всегда будет возвращать текущее значение, даже если событие было использовано.

Если есть веская причина, по которой вам нужно показать это сообщение Snackbar в обоих фрагментах, я предлагаю вам наблюдать за разными экземплярами LiveData для каждого фрагмента.

Вы можете сделать это, возвращая новый LiveData<Event<String>> каждый раз, когда вызывается viewModel.getResponseData().

person Arka Prava Basu    schedule 24.09.2019
comment
Это странно.. Мне никогда не приходилось использовать peekContent при использовании общих liveData в java, хотя это всегда работало правильно. - person Arthur Attout; 24.09.2019
comment
Вы не должны полагаться на peekContent, так как это противоречит цели создания класса Event. - person Arka Prava Basu; 24.09.2019
comment
Да и я нет. Я также не использую стратегию событий. Но я почти уверен, что у меня уже была ViewModel с LiveData, наблюдаемой несколькими фрагментами, и все они правильно обновлялись, поэтому я не понимаю, почему это не работает для OP - person Arthur Attout; 24.09.2019
comment
Оооо, я вижу, OP уже использует этот класс Event, вот почему он не работал. - person Arthur Attout; 24.09.2019