本篇将讲述对于使用ViewModel来进行Fragment之间的数据共享,使用的技术为ViewModel,dataBinding
Kotlin中使用ViewModel的数据共享
本篇已Kotlin为主要语言
本篇将讲述对于使用ViewModel来进行Fragment之间的数据共享,使用的技术为ViewModel,dataBinding
依赖
对于ViewModel是属于Androidx包下的JetPack组件,所以只需要项目使用了Androidx,就可直接使用,无需引入额外依赖包
代码教程
在进行编码之前想要做一些准备工作,给项目开启dataBinding,在项目级的build.gradle中,defaultConfig闭包下
1 | defaultConfig{ |
这样就开启了dataBinding了
创建ViewModel
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class MyViewModel : ViewModel() {
var number: MutableLiveData<Int> = MutableLiveData(0)
fun get(): MutableLiveData<Int> {
return number
}
fun add(value: Int) {
number.value = number.value?.plus(value)
}
fun set(value: Int) {
number.value = value
}
}创建一个继承ViewModel的类,在这个类中创建一个MutableLiveData的变量,并给他设置获取和设置值的方法
在Activity中获取ViewModel
1
2
3
4
5
6
7
8
9class MainActivity : AppCompatActivity() {
private lateinit var viewModel: MyViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
}
}获取ViewModel是通过ViewModelProvider(this).get(刚刚创建的ViewModel::class.java)
这里原本可以使用ViewModelProviders.of(Activity).get(刚刚创建的ViewModel::class.java),但是ViewModelProviders已经被淘汰了
接下来就是创建2个Fragment,并在Fragment中获取Activity的ViewModel
BlankFragment
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42class BlankFragment : Fragment() {
//这里创建了一个变量,将它的值设置为ActivityViewModel,括号里面只需要输入ViewModel类型即可
private val viewModel by activityViewModels<MyViewModel>()
//这个技就是当前项目的dataBinding(lateinit 代表等下进行初始化)
private lateinit var binding: FragmentBlankBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
//在这里进行dataBinding的初始化
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_blank, container, false)
initView()
return binding.root
}
private fun initView() {
//将获取完的ViewModel传给dataBinding(是因为xml文件设置了属性)
binding.data = viewModel
//设置统一的生命周期管理为父类Activity
binding.lifecycleOwner = activity
//点击按钮进行切换Fragment,是通过Navigation进行切换
binding.button.setOnClickListener {
val controller: NavController = Navigation.findNavController(it)
controller.navigate(R.id.action_blankFragment_to_detailFragment)
}
//下面的?.let{}代表当前对象不为空的时候才会执行{}内的内容
viewModel.number.value?.let { binding.seekBar.progress = it }
binding.seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {//如果插件的值变了
viewModel.number.value = p1
}
override fun onStartTrackingTouch(p0: SeekBar?) {//刚开始触摸的时候
}
override fun onStopTrackingTouch(p0: SeekBar?) {//结束触摸
}
})
}
} xml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="data"
type="com.laboratory.navviewmodel.MyViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/frameLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(data.get())}"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.222" />
<SeekBar
android:id="@+id/seekBar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="10dp"
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"
app:layout_constraintVertical_bias="0.347" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#858A8A"
android:text="进入"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>使用ConstraintLayout是为了方便进行在Design模式下进行摆放控件,上面说的所需的内容是variable中定义的,控件中就可以使用**@{定义的名称.调用方法}**
DetailFragment
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22class DetailFragment : Fragment() {
private lateinit var binding : FragmentDetailBinding
private val viewModel by activityViewModels<MyViewModel>()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = DataBindingUtil.inflate(inflater,R.layout.fragment_detail,container,false)
initView()
return binding.root
}
private fun initView() {
binding.data = viewModel
binding.lifecycleOwner = activity
binding.button.setOnClickListener {
val controller : NavController = Navigation.findNavController(it)
controller.navigate(R.id.action_detailFragment_to_blankFragment)
}
}
}和上面的Fragment功能差不多,多了两个按钮,进行增加和删除
xml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<layout 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">
<data>
<variable
name="data"
type="com.laboratory.navviewmodel.MyViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".DetailFragment">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(data.number)}"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.192" />
<Button
android:id="@+id/add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="+"
android:onClick="@{()->data.add(1)}"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="@+id/reduce"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/reduce"
app:layout_constraintTop_toTopOf="@+id/reduce"
app:layout_constraintVertical_bias="0.0" />
<Button
android:id="@+id/reduce"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="-"
android:onClick="@{()->data.add(-1)}"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/add"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.391" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="返回"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.535" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>在使用了dataBinding中,连点击事件都可以在xml中设置,只需要想 onClick=”@{()->对象.方法}” 这样去使用
这样全局都是使用统一的ViewModel来获取数据,也就可以进行数据共享