一般Android Studio中自动生成的ViewModel代码,其基类是无参数的ViewModel()。
TestViewModel:
import androidx.lifecycle.ViewModel
class TestViewModel : ViewModel() {
// TODO: Implement the ViewModel
}
TestFragment:
import androidx.fragment.app.viewModels
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
class TestFragment : Fragment() {
companion object {
fun newInstance() = TestFragment()
}
private val viewModel: TestViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// TODO: Use the ViewModel
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.fragment_test, container, false)
}
}
以上是自动生成的在Fragment中使用ViewModel的方法。
如果想自定义参数,通常需要定义一个自定义的工厂方法。
但是,如果希望在ViewModel中获得一个context参数,则可以使用AndroidViewModel方法。
package com.example.test
import android.app.Application
import androidx.lifecycle.AndroidViewModel
class TestViewModel(app: Application) : AndroidViewModel(app) {
// TODO: Implement the ViewModel
}
在Fragment中实例化该ViewModel的代码与普通的ViewModel实例化方法相同。
/**
*另一种实例化的方法,实现功能相同
*/
lateinit var viewModel: TestViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel = ViewModelProvider(this).get(TestViewModel::class.java)
// TODO: Use the ViewModel
}
上面这段代码和上面提到的自动生成的代码实现功能基本上是一样的。
实际应用中,如果期望能够在ViewModel内获得一个context参数,例如Room数据库中实例化dao和db,或是有需要放在ViewModel中但是需要context参数的代码,则可以使用该方法。
举例:在ViewModel中使用Toast:
ViewModel:
class TestViewModel(private val app: Application) : AndroidViewModel(app) {
fun showInfo(){
Toast.makeText(app, "从ViewModel中调用的方法", Toast.LENGTH_LONG).show()
}
}
Fragment:
class TestFragment : Fragment() {
lateinit var viewModel: TestViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel = ViewModelProvider(this).get(TestViewModel::class.java)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
val root = inflater.inflate(R.layout.fragment_test, container, false)
val btnShow = root.findViewById<Button>(R.id.btnShow)
btnShow.setOnClickListener {
viewModel.showInfo()
}
return root
}
}
activity_main.xml:
<!--这里是为了在Activity中显示Fragment,因此添加了FragmentContainerView控件-->
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragmentContainerView"
android:name="com.example.test.TestFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
TestFragment:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".TestFragment">
<Button
android:id="@+id/btnShow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="点击显示Toast" />
</FrameLayout>
显示效果:
笔者建议:
1、上述例子只是演示功能,实际中如果想要使用Toast或者其他更新UI的方法,请注意不要尝试在后台执行的代码中更新UI显示界面。
2、在ViewModel中获取context实例可能导致内存泄漏的问题,不过使用该方法应该能从一定程度上避免该问题。
附依赖文件:
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout)
implementation(libs.androidx.legacy.support.v4)
implementation(libs.androidx.lifecycle.livedata.ktx)
implementation(libs.androidx.lifecycle.viewmodel.ktx)
implementation(libs.androidx.fragment.ktx)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
}
//以上代码是创建带有ViewModel的Fragment时自动生成的