Android jetpack ViewModel+LiveData+Fragment 间通讯

参考:2021年最全面的Jetpack系统学习课程,看他就够了,更新中_哔哩哔哩_bilibili

要求 上下各两个进度条。分别来自两个Fragment。当第一个的progress发生改变的时候。第二个progress同时跟着改变

页面

package com.anguomob.jecpack.activity

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.anguomob.jecpack.R
import com.anguomob.jecpack.databinding.ActivityLiveDataBinding
import com.anguomob.jecpack.databinding.ActivityLiveDataFragmentBinding

class LiveDataFragmentActivity : AppCompatActivity() {
    lateinit var binding: ActivityLiveDataFragmentBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding=ActivityLiveDataFragmentBinding.inflate(layoutInflater)
        setContentView(binding.root)
    }
}

 布局包含了两个Fragment

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".activity.LiveDataFragmentActivity">


    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.5" />

    <fragment
        android:id="@+id/seekBar1"
        android:name="com.anguomob.jecpack.fragment.SeekBarFragmentOne"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/guideline4"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <fragment
        android:id="@+id/seekBar2"
        android:name="com.anguomob.jecpack.fragment.SeekBarFragmentTwo"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/guideline4" />

</androidx.constraintlayout.widget.ConstraintLayout>

guideLine 上下分别为两个Fragment

SeekBarFragmentOne
package com.anguomob.jecpack.fragment

import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
import androidx.lifecycle.ViewModelProvider
import com.anguomob.jecpack.R
import com.anguomob.jecpack.databinding.FragmentSeekBar1Binding
import com.anguomob.jecpack.databinding.FragmentSeekBar2Binding
import com.anguomob.jecpack.viewmodel.LiveDataFragmentViewModel

// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"

/**
 * A simple [Fragment] subclass.
 * Use the [SeekBarFragment1.newInstance] factory method to
 * create an instance of this fragment.
 */
class SeekBarFragmentOne : Fragment() {
    private  val TAG = "SeekBarFragmentOne"
    // TODO: Rename and change types of parameters
    private var param1: String? = null
    private var param2: String? = null

    lateinit var bar1Binding: FragmentSeekBar1Binding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            param1 = it.getString(ARG_PARAM1)
            param2 = it.getString(ARG_PARAM2)
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        bar1Binding = FragmentSeekBar1Binding.inflate(inflater)
        val viewModel = ViewModelProvider(
            requireActivity(),
            ViewModelProvider.AndroidViewModelFactory(requireActivity().application)
        ).get(
            LiveDataFragmentViewModel::class.java
        )

        viewModel.getProgress().observe(requireActivity(), { progress ->
            Log.e(TAG,"SeekBarFragmentOne ${progress}")

            bar1Binding.seekBar1.progress = progress;
        })
        bar1Binding.seekBar1.setOnSeekBarChangeListener(object: OnSeekBarChangeListener{
            override fun onProgressChanged(p0: SeekBar?, progress: Int, p2: Boolean) {
                if( viewModel.getProgress().value==progress){
                    return
                }

                viewModel.getProgress().value=progress
            }

            override fun onStartTrackingTouch(p0: SeekBar?) {
            }

            override fun onStopTrackingTouch(p0: SeekBar?) {
            }
        } )
//
        // Inflate the layout for this fragment
        return bar1Binding.root
    }

    companion object {
        /**
         * Use this factory method to create a new instance of
         * this fragment using the provided parameters.
         *
         * @param param1 Parameter 1.
         * @param param2 Parameter 2.
         * @return A new instance of fragment SeekBarFragment1.
         */
        // TODO: Rename and change types and number of parameters
        @JvmStatic
        fun newInstance(param1: String, param2: String) =
            SeekBarFragmentOne().apply {
                arguments = Bundle().apply {
                    putString(ARG_PARAM1, param1)
                    putString(ARG_PARAM2, param2)
                }
            }
    }
}

其布局文件为一个seekbar

<?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"
 >

    <!-- TODO: Update blank fragment layout -->
    <SeekBar
        android:id="@+id/seekBar1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/hello_blank_fragment" />

</FrameLayout>

。。。

SeekBarFragmentTwo 和one一模一样。,
package com.anguomob.jecpack.fragment

import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.SeekBar
import androidx.lifecycle.ViewModelProvider
import com.anguomob.jecpack.R
import com.anguomob.jecpack.databinding.FragmentSeekBar1Binding
import com.anguomob.jecpack.databinding.FragmentSeekBar2Binding
import com.anguomob.jecpack.viewmodel.LiveDataFragmentViewModel

// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"

/**
 * A simple [Fragment] subclass.
 * Use the [SeekBarFragment1.newInstance] factory method to
 * create an instance of this fragment.
 */
class SeekBarFragmentTwo : Fragment() {
    private  val TAG = "SeekBarFragmentTwo"
    // TODO: Rename and change types of parameters
    private var param1: String? = null
    private var param2: String? = null
    lateinit var bar2Binding: FragmentSeekBar2Binding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            param1 = it.getString(ARG_PARAM1)
            param2 = it.getString(ARG_PARAM2)
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        bar2Binding= FragmentSeekBar2Binding.inflate(inflater)
        // Inflate the layout for this fragment
        val viewModel = ViewModelProvider(
            requireActivity(),
            ViewModelProvider.AndroidViewModelFactory(requireActivity().application)
        ).get(
            LiveDataFragmentViewModel::class.java
        )

        viewModel.getProgress().observe(requireActivity(), { progress ->
            Log.e(TAG,"SeekBarFragmentOne ${progress}")

            bar2Binding.seekBar2.progress = progress;
        })
        bar2Binding.seekBar2.setOnSeekBarChangeListener(object: SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(p0: SeekBar?, progress: Int, p2: Boolean) {
                if( viewModel.getProgress().value==progress){
                    return
                }
                viewModel.getProgress().value=progress
            }

            override fun onStartTrackingTouch(p0: SeekBar?) {
            }

            override fun onStopTrackingTouch(p0: SeekBar?) {
            }
        } )
        return bar2Binding.root
    }

    companion object {
        /**
         * Use this factory method to create a new instance of
         * this fragment using the provided parameters.
         *
         * @param param1 Parameter 1.
         * @param param2 Parameter 2.
         * @return A new instance of fragment SeekBarFragment1.
         */
        // TODO: Rename and change types and number of parameters
        @JvmStatic
        fun newInstance(param1: String, param2: String) =
            SeekBarFragmentTwo().apply {
                arguments = Bundle().apply {
                    putString(ARG_PARAM1, param1)
                    putString(ARG_PARAM2, param2)
                }
            }
    }
}

<?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"
    >

    <!-- TODO: Update blank fragment layout -->
    <SeekBar
        android:id="@+id/seekBar2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/hello_blank_fragment" />

</FrameLayout>

然而

核心代码却和上篇博客差不多

package com.anguomob.jecpack.viewmodel

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel

class LiveDataFragmentViewModel : ViewModel() {
    private lateinit var progress: MutableLiveData<Int>

    fun getProgress(): MutableLiveData<Int> {
        if (::progress.isInitialized.not()) {
            progress = MutableLiveData();
            progress.value = 0;
        }
        return progress
    }
}

猜你喜欢

转载自blog.csdn.net/mp624183768/article/details/124888663