我应该在 ViewModel 中包含 LifecycleOwner 吗?

问题描述 投票:0回答:4

当前需要 LifecycleOwner 才能创建观察者。

我有在 ViewModel 中创建观察者的代码,因此我在片段中检索 ViewModel 时附加了 LifecycleOwner。

根据谷歌的文档。

警告:ViewModel 绝不能引用视图、生命周期或任何可能保存对活动上下文的引用的类。

我是否违反了该警告?如果违反了,您建议我以什么方式移动观察者的创建以返回数据?

我只做了一个观察者,所以我想知道它是否仍然有效。因为谷歌的文档中也提到了。

ViewModel 对象可以包含 LifecycleObservers,例如 LiveData 对象。

主要片段

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
}

主视图模型

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:感谢 @pskink 使用转换的建议,改进了 ViewModel。

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
}
android mvvm android-viewmodel
4个回答
83
投票

不。如果您想观察

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()
}

3
投票

假设:

  1. Fuel
    指的是您的
    ViewModel
  2. Fuel.request(IpAddressApi.MyIp())
    是您
    ViewModel
  3. 中的一种方法
  4. IpAddressApi.MyIp()
    没有参考您的
    LifecycleOwner

如果一切属实,那么您就没有违反。只要您不传递

LifecycleOwner
引用到
ViewModel
,您就是安全的!

LifecycleOwner - 与 Activity 或 Fragment 相关,因为它拥有各种 Android 生命周期,例如 onCreate、onPause、onDestroy 等


1
投票

Kotlin 中,这可能是这样的:

val mObserver = Observer<List<QueueTabData>> { myString->
// do something with myString
}

1
投票

我应该在 ViewModel 中包含 LifecycleOwner 吗?
答:没有

viewmodel
的目的是保存UI数据,以便它在配置更改后仍然存在。
原因如下

警告:ViewModel 绝不能引用视图、生命周期或任何可能保存对活动上下文的引用的类。

是因为

viewmodel
在配置更改后仍然存在,而
activities
则不然。它们在配置更改时被销毁并重新创建。因此,如果视图模型中有任何活动上下文引用,它们将引用之前被销毁的活动。

所以这会导致内存泄漏。所以不推荐。

此外,

如果您有

repositories
作为数据源,我们应该避免将
LiveData
用于代码块上方段落中提到的目的。 这是因为
LiveData
 是在 
MainThread
 上处理的,可能会导致 UI 冻结。

我们应该将

kotlin flows

 用于此类目的。

© www.soinside.com 2019 - 2024. All rights reserved.