Следует ли включать LifecycleOwner в ViewModel?

LifecycleOwner в настоящее время нужен мне для создания наблюдателя.

У меня есть код, который создает Observer в ViewModel, поэтому я присоединяю LifecycleOwner при получении ViewModel в моем фрагменте.

Согласно документации Google.

Предупреждение: ViewModel никогда не должен ссылаться на представление, жизненный цикл или любой класс, который может содержать ссылку на контекст действия.

Нарушил ли я это предупреждение, и если да, то каким образом вы порекомендуете мне переместить создание наблюдателя для возврата данных?

Я сделал только наблюдателя, поэтому мне интересно, действительно ли это. Так как также в документации Google это тоже сказано.

Объекты ViewModel могут содержать LifecycleObservers, например объекты LiveData.

MainFragment

private lateinit var model: MainViewModel

/**
 * Observer for our ViewModel IpAddress LiveData value.
 * @see Observer.onChanged
 * */
private val ipObserver = Observer<String> {
    textIp.text = it
    hideProgressBar()
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    model = ViewModelProviders.of(this).get(MainViewModel::class.java)
    model.attach(this)
}

override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? =
        inflater?.inflate(R.layout.fragment_main, container, false)

override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    buttonRetrieveIp.setOnClickListener {
        showProgressBar()
        model.fetchMyIp().observe(this, ipObserver) //Here we attach our ipObserver
    }
}

override fun showProgressBar() {

    textIp.visibility = View.GONE
    progressBar.visibility = View.VISIBLE
}

override fun hideProgressBar() {

    progressBar.visibility = View.GONE
    textIp.visibility = View.VISIBLE
}

MainViewModel

private var ipAddress = MutableLiveData<String>()
private lateinit var owner: LifecycleOwner

fun attach(fragment: MainFragment) {
    owner = fragment
}

/**
 * For more information regarding Fuel Request using Fuel Routing and Live Data Response.
 * @see <a href="https://github.com/kittinunf/Fuel#routing-support">Fuel Routing Support</a>
 * @see <a href="https://github.com/kittinunf/Fuel#livedata-support">Fuel LiveData Support</a>
 * */
fun fetchMyIp(): LiveData<String> {

    Fuel.request(IpAddressApi.MyIp())
            .liveDataResponse()
            .observe(owner, Observer {

                if (it?.first?.statusCode == 200) {//If you want you can add a status code checker here.

                    it.second.success {

                        ipAddress.value = Ip.toIp(String(it))?.ip
                    }
                }
            })
    return ipAddress
}

Обновление 1. Улучшенная ViewModel благодаря предложению @pskink об использовании преобразований.

private lateinit var ipAddress:LiveData<String>

/**
 * Improved ViewModel since January 23, 2018 credits to <a href="https://stackoverflow.com/users/2252830/pskink">pskink</a> <a href="
 *
 * For more information regarding Fuel Request using Fuel Routing and Live Data Response.
 * @see <a href="https://github.com/kittinunf/Fuel#routing-support">Fuel Routing Support</a>
 * @see <a href="https://github.com/kittinunf/Fuel#livedata-support">Fuel LiveData Support</a>
 * */
fun fetchMyIp(): LiveData<String> {

    ipAddress = Transformations.map(Fuel.request(IpAddressApi.MyIp()).liveDataResponse(), {

        var ip:String? = ""

            it.second.success {

                ip = Ip.toIp(String(it))?.ip
            }
        ip
    })

    return ipAddress
}

person Hiroga Katageri    schedule 23.01.2018    source источник
comment
пробовали MediatorLiveData или Transformations#map / Transformations#switchMap?   -  person pskink    schedule 23.01.2018
comment
На самом деле я еще этого не сделал, поэтому вместо того, чтобы возвращать строку LiveData, я верну MediatorLiveData и добавлю оба источника и добавлю одного наблюдателя в свой фрагмент, верно?   -  person Hiroga Katageri    schedule 23.01.2018
comment
сначала попробуйте класс Transformations - кажется, это самый простой способ - если нет, то когда дело доходит до MediatorLiveData, что вы имеете в виду под обоими источниками? есть один источник, который меняется, не так ли?   -  person pskink    schedule 23.01.2018
comment
Плохо, я получаю только источник из моего метода GET. Хм ... Я попытался обернуть liveDataResponse () в Transformations.map, но он не вызывает мой метод GET. prntscr.com/i4bnhe Я определенно делаю здесь что-то не так.   -  person Hiroga Katageri    schedule 23.01.2018
comment
см. Преобразование LiveData   -  person pskink    schedule 23.01.2018
comment
Я получил это сейчас, я смог заставить его работать с помощью Transformations.   -  person Hiroga Katageri    schedule 23.01.2018


Ответы (2)


Нет. Если вы хотите наблюдать за изменениями некоторых LiveData внутри вашего ViewModel, вы можете использовать observeForever(), который не требует LifecycleOwner.

Не забудьте удалить этого наблюдателя на событии ViewModel onCleared():

val observer = new Observer() {
  override public void onChanged(Integer integer) {
    //Do something with "integer"
  }
}

...

liveData.observeForever(observer);

...

override fun onCleared() {
    liveData.removeObserver(observer) 
    super.onCleared()
}

Очень хорошая ссылка с примерами наблюдения LiveData.

person Vitaliy A    schedule 18.07.2019

Предположения:

  1. Fuel относится к вашему ViewModel
  2. Fuel.request(IpAddressApi.MyIp()) - это метод в вашем ViewModel
  3. IpAddressApi.MyIp() не имеет ссылки на ваш LifecycleOwner,

Если все верно, то вы его не нарушаете. Пока вы не передаете LifecycleOwner ссылку на ViewModel, вы в безопасности!

LifecycleOwner - относится к действию или фрагменту, поскольку ему принадлежат различные жизненные циклы Android, например onCreate, onPause, onDestroy и т. д.

person martinomburajr    schedule 23.01.2018
comment
Я добавил в свой вопрос дополнительную информацию. Fuel - это мой HttpClient, Fuel.request - это метод в Fuel, который преобразует интерфейс FuelRouting в запрос, в котором я создаю наблюдателя для возврата из моего метода GET. - person Hiroga Katageri; 23.01.2018