使用LiveData、ViewModel在Activity和Fragment,Fragment和Fragment之间共享数据

发布时间 2023-08-11 12:08:06作者: 飘杨......

一、概述

  传统的Activity与Fragment之间共享数据,Fragment与Fragment之间共享数据,我一般会采用EventBus事件总线来实现。不过现在可以借助另外一种简单的方式LiveData+ViewModel也可以实现这种共享

二、代码示例

  示例描述:要求FragmentA发送出数据,FragmentB和Activity都能接收到。FragmentB发送出的数据FragmentA和Activity都能接收到。Activity发送出去的数据FragmentA和FragmentB都能接收到。

  上代码:

  SharedDataActivity.kt用于承载两个Fragment以及自己数据的Activity

/**
 * Activity和Fragment,Fragment和Fragment之间共享数据
 */
class ShareDataActivity :AppCompatActivity(){
    private var mModel:UserViewModel?=null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_share_data)
        //第一种实现方式
        mModel = ViewModelProvider(this,ViewModelProvider.AndroidViewModelFactory.getInstance(com.tony.demo.utils.ContextUtils.getApplicationContext())).get(UserViewModel::class.java)
        //第二种实现方式
//        mModel = ViewModelProvider(this).get(UserViewModel::class.java)
        supportFragmentManager.beginTransaction().replace(R.id.fl_continer1,FragmentA()).commit()
        supportFragmentManager.beginTransaction().replace(R.id.fl_continer2, FragmentB()).commit()

        btnSendToActivity.setOnClickListener {
            mModel?.getAccount()?.postValue(AccountBean("Activity的数据:杨洛峋",5))
        }

        mModel?.getAccount()?.observe(this){
            tvContentActivity.text = "接收到来自${it.name} ${it.age} 岁了!"
        }

    }
}

 activity_shared_data.layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:weightSum="3">

    <FrameLayout
        android:id="@+id/fl_continer1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1" />

    <FrameLayout
        android:id="@+id/fl_continer2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1" />

    <RelativeLayout
        android:id="@+id/fl_continer3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1">

        <Button
            android:id="@+id/btnSendToActivity"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Activity发送消息" />

        <TextView
            android:id="@+id/tvContentActivity"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="" />
    </RelativeLayout>
</LinearLayout>

FragmentA.kt

/**
 * 使用LiveData+ViewModel让A和B进行通信
 */
class FragmentA : Fragment(){
    private var mModel: UserViewModel? = null
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_a, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        //第一种实现方式
//        mModel = ViewModelProvider(requireActivity()).get(UserViewModel::class.java)
        //第二种实现方式
        mModel = ViewModelProvider(requireActivity(),
            ViewModelProvider.AndroidViewModelFactory.getInstance(ContextUtils.getApplicationContext()))
            .get(UserViewModel::class.java)
        btnSendToB.setOnClickListener {
            //A向B发送数据
            mModel?.getAccount()?.postValue(AccountBean("FragmentA的消息:杨洛峋",5))
        }
        //当数据有变化的时候执行此方法
        mModel?.getAccount()?.observe(requireActivity()) {
            tvContentA.text = "接收到来自${it.name} ${it.age} 岁了!"
        }

    }

}

fragment_a.layout

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/btnSendToB"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="A发送消息"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tvContentA"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        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>

FragmentB.kt

/**
 * 使用LiveData+ViewModel让A和B进行通信
 */
class FragmentB : Fragment() {

    private var mModel: UserViewModel? = null
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_b, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        //第一种实现方式
//        mModel = ViewModelProvider(requireActivity()).get(UserViewModel::class.java)
        //第二种实现方式
        mModel = ViewModelProvider(requireActivity(),ViewModelProvider.AndroidViewModelFactory.getInstance(ContextUtils.getApplicationContext())).get(UserViewModel::class.java)
        btnSendToA.setOnClickListener {
            mModel?.getAccount()?.postValue(AccountBean("FragmentB的消息:杨洛峋小宝宝",5))
        }

        mModel?.getAccount()?.observe(requireActivity()){
            tvContentB.text = "接收到来自${it.name} ${it.age} 岁了!"
        }
    }
}

framgent_b.layout

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/btnSendToA"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="B发送消息"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tvContentB"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        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>

  运行测试结果: