想要在 android 个片段之间使用 livedata、viewmodel 传输数据

Want to transfer data using livedata, viewmodel between in android fragments

我目前正在尝试制作一个计算贷款计划的应用程序。用户绘制贷款金额、首付年限以及贷款应支付的租金等数据。我已经为贷款金额、两个年搜索栏和租金号码实现了编辑文本。

由于我是 android 编程的新手,所以我自然而然地努力在我的应用程序中实现 MVVM。我实现了数据绑定、视图模型并将代码编写到 link 它们一起。如果我在 viewmodel 中使用 Init,我也会得到值,但我似乎没有将 Int 值从 seekbar 转移到下一个片段。有人对我的代码有建议吗?

非常感谢您的帮助。


在 AnnuitetFragment.kt 片段中,我只将 modelView 实现到 RenterAnnSeekBar,因为我将它用于测试。

package com.example.lnognedbetalingsplan.annuitet

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.SeekBar
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import com.example.lnognedbetalingsplan.R
import com.example.lnognedbetalingsplan.databinding.FragmentAnnuitetBinding
import com.example.lnognedbetalingsplan.viewmodel.AnnuitetViewModel


class AnnuitetFragment : Fragment() {

    private var _binding: FragmentAnnuitetBinding? = null
    private val binding get() = _binding!!


    private lateinit var viewModel: AnnuitetViewModel


    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View {

        _binding = FragmentAnnuitetBinding.inflate(inflater, container, false)
        return binding.root
    }

        var startPoint = 0
        var endPoint = 0

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

            binding.lifecycleOwner = this
            viewModel = ViewModelProvider(this)[AnnuitetViewModel::class.java]
            binding.viewmodel = viewModel




            binding.tilbakeTilVelkommen.setOnClickListener {
                findNavController().navigate(R.id.action_annuitetFragment_to_velkommenFragment)
            }
            binding.BeregnLaanAnnuitet.setOnClickListener {
                findNavController().navigate(R.id.action_annuitetFragment_to_annuitetPlanFragment)
            }


            binding.RenterAnnSeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
                override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                    binding.RenterTall.text = progress.toString()
                }

                override fun onStartTrackingTouch(seekBar: SeekBar?) {
                    if (seekBar != null){
                        startPoint = seekBar.progress
                    }

                }

                override fun onStopTrackingTouch(seekBar: SeekBar?) {
                    if (seekBar != null){
                        endPoint = seekBar.progress
                    }
                }
            })

            binding.AarSerieSeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
                override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                    binding.AarTall.text = progress.toString()
                }

                override fun onStartTrackingTouch(seekBar: SeekBar?) {
                    if (seekBar != null){
                        startPoint = seekBar.progress
                    }

                }

                override fun onStopTrackingTouch(seekBar: SeekBar?) {
                    if (seekBar != null){
                        endPoint = seekBar.progress
                    }
                }
            })


    }
}

AnnuitetViewModel.kt 是视图模型 class 我将用来存储实时数据,以便它可以在 AnnuitetFragment.kt 和 AnnuitetPlanFragment.kt 之间共享。如果此代码遗漏任何内容,请帮助我一些指示。

package com.example.lnognedbetalingsplan.viewmodel

import android.widget.SeekBar
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import androidx.lifecycle.ViewModel

open class AnnuitetViewModel : ViewModel() {

    val progress: MutableLiveData<Int> by lazy { MutableLiveData<Int>() }

    val renterProgress: LiveData<Int>
        get() = progress

    init {
        progress.value = 1
    }
}

我的计划AnnuitetPlanFragment.kt是从AnnuitetFragment.kt获取数据并计算用户的贷款计划。但是当我尝试从 AnnuitViewModel.kt 获取数据时,我从 Init 获取了模拟数据,但没有来自 val progress.

的数据
package com.example.lnognedbetalingsplan.annuitet

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import com.example.lnognedbetalingsplan.R
import com.example.lnognedbetalingsplan.databinding.FragmentAnnuitetBinding
import com.example.lnognedbetalingsplan.databinding.FragmentAnnuitetPlanBinding

import com.example.lnognedbetalingsplan.viewmodel.AnnuitetViewModel
import kotlin.math.pow

class AnnuitetPlanFragment : Fragment() {

    private var _binding: FragmentAnnuitetPlanBinding? = null
    private val binding get() = _binding!!

    private lateinit var viewModel: AnnuitetViewModel

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                                savedInstanceState: Bundle?): View? {
        _binding = FragmentAnnuitetPlanBinding.inflate(inflater, container, false)
        return binding.root
    }

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

        binding.lifecycleOwner = this
        viewModel = ViewModelProvider(this).get(AnnuitetViewModel::class.java)
        binding.viewmodel = viewModel

        viewModel.renterProgress.observe(viewLifecycleOwner, Observer { renteTall->
            binding.tvTest.text = renteTall.toString()
        })



        binding.tilbakeTilAnnuitet.setOnClickListener {
            findNavController().navigate(R.id.action_annuitetPlanFragment_to_annuitetFragment)
        }

    }
}

最后一个是我的 fragment_annuitet.xml,我在其中实现了数据绑定,搜索栏获取进度数据并将其显示在 viewCreate 中。

<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>
                <import type="android.view.View"/>
                <variable
                    name="viewmodel"
                    type="com.example.lnognedbetalingsplan.viewmodel.AnnuitetViewModel" />
        </data>

        <androidx.constraintlayout.widget.ConstraintLayout
                android:id="@+id/annuitet_layout"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:context=".annuitet.AnnuitetFragment">

                <SeekBar
                    android:id="@+id/RenterAnnSeekBar"
                    android:layout_width="300dp"
                    android:layout_height="30dp"
                    android:max="50"
                    android:min="0"
                    android:progress="@={viewmodel.progress}"
                    app:layout_constraintBottom_toTopOf="@+id/AarSerieSeekBar"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintHorizontal_bias="0.306"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintVertical_bias="0.84" />

                <SeekBar
                    android:id="@+id/AarSerieSeekBar"
                    android:layout_width="300dp"
                    android:layout_height="30dp"
                    android:max="50"
                    android:min="0"
                    android:progress="5"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintHorizontal_bias="0.306"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintVertical_bias="0.499" />

                <EditText
                    android:id="@+id/laanebelop"
                    android:layout_width="196dp"
                    android:layout_height="56dp"
                    android:autofillHints=""
                    android:ems="10"
                    android:hint="@string/hint"
                    android:inputType="numberDecimal"
                    android:textColorHint="#757575"
                    android:visibility="visible"
                    android:text=""
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintHorizontal_bias="0.641"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintVertical_bias="0.248" />

                <TextView
                    android:id="@+id/Laanebelop"
                    android:layout_width="103dp"
                    android:layout_height="40dp"
                    android:layout_marginTop="184dp"
                    android:text="@string/laaneBeløp"
                    android:textSize="20sp"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintHorizontal_bias="0.11"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />

                <TextView
                    android:id="@+id/AarTall"
                    android:layout_width="35dp"
                    android:layout_height="30dp"
                    android:text="@string/_5"
                    android:textSize="20sp"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintHorizontal_bias="0.619"
                    app:layout_constraintStart_toEndOf="@+id/AarSerieSeekBar"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintVertical_bias="0.499" />

                <TextView
                    android:id="@+id/RenterTall"
                    android:layout_width="35dp"
                    android:layout_height="30dp"
                    android:text="@={`` + viewmodel.progress}"
                    android:textSize="20sp"
                    android:visibility="@{viewmodel.progress != null? View.VISIBLE : View.GONE}"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintHorizontal_bias="0.633"
                    app:layout_constraintStart_toEndOf="@+id/RenterAnnSeekBar"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintVertical_bias="0.383" />

                <TextView
                    android:id="@+id/Rentenummer"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@string/velg_rente"
                    app:layout_constraintBottom_toTopOf="@+id/RenterAnnSeekBar"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintHorizontal_bias="0.097"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/Laanebelop"
                    app:layout_constraintVertical_bias="0.692" />

                <TextView
                    android:id="@+id/antallAar"
                    android:layout_width="62dp"
                    android:layout_height="21dp"
                    android:text="@string/antall_aar"
                    app:layout_constraintBottom_toTopOf="@+id/AarSerieSeekBar"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintHorizontal_bias="0.097"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/RenterAnnSeekBar"
                    app:layout_constraintVertical_bias="0.666" />

                <Button
                    android:id="@+id/BeregnLaanAnnuitet"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginBottom="264dp"
                    android:text="@string/bergen_l_net"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintHorizontal_bias="0.757"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/AarSerieSeekBar"
                    app:layout_constraintVertical_bias="1.0" />

                <Button
                    android:id="@+id/tilbakeTilVelkommen"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="24dp"
                    android:layout_marginEnd="68dp"
                    android:text="@string/tilbake"
                    app:layout_constraintBottom_toTopOf="@+id/laanebelop"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintVertical_bias="0.0" />

                <TextView
                    android:id="@+id/textView2"
                    android:layout_width="180dp"
                    android:layout_height="40dp"
                    android:layout_marginStart="32dp"
                    android:layout_marginTop="24dp"
                    android:text="@string/annuitet_l_n"
                    android:textStyle="bold"
                    android:textSize="30sp"
                    app:layout_constraintBottom_toTopOf="@+id/Laanebelop"
                    app:layout_constraintEnd_toStartOf="@+id/tilbakeTilVelkommen"
                    app:layout_constraintHorizontal_bias="0.0"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintVertical_bias="0.066" />

        </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

我想出了我自己的问题。

如果发现您与两个要共享数据的片段共享您的模型视图,并且与观察者共享,这是可能的。

添加了这段代码:

private val AnnuitetViewModel: AnnuitetViewModel by activityViewModels()

还为我想转移到下一个片段的每个 val 创建了观察者:

AnnuitetViewModel.loanNumber.observe(viewLifecycleOwner){loanNumber->
                binding.laanebelop.setText(loanNumber)
            }

            AnnuitetViewModel.progressRenter.observe(viewLifecycleOwner){progressRenter->
                binding.RenterTall.text = progressRenter
            }

            AnnuitetViewModel.progressAar.observe(viewLifecycleOwner){progressAar->
                binding.AarTall.text = progressAar
            }

按钮侦听器触发向视图模型中的实时数据传输:

binding.BeregnLaanAnnuitet.setOnClickListener {
                AnnuitetViewModel.saveLoanNumber(binding.laanebelop.text.toString())
                AnnuitetViewModel.saveProgressRenter(binding.RenterTall.text.toString())
                AnnuitetViewModel.saveProgressAar(binding.AarTall.text.toString())
                findNavController().navigate(R.id.action_annuitetFragment_to_annuitetPlanFragment)
            }

在 viewModel 中,我制作了一些 var 和 val 来接收数据:

open class AnnuitetViewModel : ViewModel() {

    var startPoint = 0
    var endPoint = 0

    val seekbarRenterProgress: MutableLiveData<Int> by lazy { MutableLiveData<Int>() }
    val seekbarAarProgress: MutableLiveData<Int> by lazy { MutableLiveData<Int>() }

    private var _loanNumber = MutableLiveData<String>()
    val loanNumber: MutableLiveData<String> = _loanNumber

    fun saveLoanNumber(newLoanNumber: String){
        _loanNumber.value = newLoanNumber
    }

    private var _progressRenter = MutableLiveData<String>()
    val progressRenter: MutableLiveData<String> = _progressRenter

    fun saveProgressRenter(newProgressRenter: String){
        _progressRenter.value = newProgressRenter
    }

    private var _progressAar = MutableLiveData<String>()
    val progressAar: MutableLiveData<String> = _progressAar

    fun saveProgressAar(newProgressAar: String){
        _progressAar.value = newProgressAar
    }

    init {
        seekbarRenterProgress.value = 5
        seekbarAarProgress.value = 5
    }
}

seekBar 和 textview 在我的 xml 中看起来像这样:

                <SeekBar
                    android:id="@+id/AarSerieSeekBar"
                    android:layout_width="300dp"
                    android:layout_height="30dp"
                    android:max="50"
                    android:min="0"
                    android:progress="@={viewmodel.seekbarAarProgress}"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintHorizontal_bias="0.306"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintVertical_bias="0.499" />

<TextView
                    android:id="@+id/AarTall"
                    android:layout_width="35dp"
                    android:layout_height="30dp"
                    android:text="@={`` + viewmodel.seekbarAarProgress}"
                    android:textSize="20sp"
                    android:visibility="@{viewmodel.seekbarAarProgress != null? View.VISIBLE : View.GONE}"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintHorizontal_bias="0.619"
                    app:layout_constraintStart_toEndOf="@+id/AarSerieSeekBar"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintVertical_bias="0.499" />

为了测试第二个片段是否可以读取数据,我编写了这段代码来观察数据并将其发送到当您 运行 模拟器中的应用程序时出现的文本视图:

AnnuitetViewModel.loanNumber.observe(viewLifecycleOwner, binding.tvTest::setText)
AnnuitetViewModel.progressRenter.observe(viewLifecycleOwner, binding.tvTest2::setText)
AnnuitetViewModel.progressRenter.observe(viewLifecycleOwner, binding.tvTest3::setText)