当前位置 博文首页 > 灵剑山真人:fragment之间相互传数据、共享数据

    灵剑山真人:fragment之间相互传数据、共享数据

    作者:灵剑山真人 时间:2021-05-31 18:20

    在 Fragment 之间共享数据

    Activity 中的两个或更多 Fragment 需要相互通信是一种很常见的现象。想象一下拆分视图 (master-detail) Fragment 的常见情况,假设您有一个 Fragment,在该 Fragment 中,用户从列表中选择一项,还有另一个 Fragment,用于显示选定项的内容。这种情况不太容易处理,因为这两个 Fragment 都需要定义某种接口描述,并且所有者 Activity 必须将两者绑定在一起。此外,这两个 Fragment 都必须处理另一个 Fragment 尚未创建或不可见的情况。

    可以使用 ViewModel 对象解决这一常见的难点。这两个 Fragment 可以使用其 Activity 范围共享 ViewModel 来处理此类通信,如以下示例代码所示:

    class SharedViewModel : ViewModel() {
        val selected = MutableLiveData<Item>()
    
        fun select(item: Item) {
            selected.value = item
        }
    }
    
    class MasterFragment : Fragment() {
    
        private lateinit var itemSelector: Selector
    
        // Use the 'by activityViewModels()' Kotlin property delegate
        // from the fragment-ktx artifact
        private val model: SharedViewModel by activityViewModels()
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            itemSelector.setOnClickListener { item ->
                // Update the UI
            }
        }
    }
    
    class DetailFragment : Fragment() {
    
        // Use the 'by activityViewModels()' Kotlin property delegate
        // from the fragment-ktx artifact
        private val model: SharedViewModel by activityViewModels()
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            model.selected.observe(viewLifecycleOwner, Observer<Item> { item ->
                // Update the UI
            })
        }
    }

    请注意,这两个 Fragment 都会检索包含它们的 Activity。这样,当这两个 Fragment 各自获取 ViewModelProvider 时,它们会收到相同的 SharedViewModel 实例(其范围限定为该 Activity)。

    此方法具有以下优势:

    • Activity 不需要执行任何操作,也不需要对此通信有任何了解。
    • 除了 SharedViewModel 约定之外,Fragment 不需要相互了解。如果其中一个 Fragment 消失,另一个 Fragment 将继续照常工作。
    • 每个 Fragment 都有自己的生命周期,而不受另一个 Fragment 的生命周期的影响。如果一个 Fragment 替换另一个 Fragment,界面将继续工作而没有任何问题。

     

    当在其中一个fragment中修改了数据,希望另外一个fragment的数据也可以被修改。使用“共享 view model”的方式避免了一大堆炒鸡繁琐的回调接口。

    class DatePickerFragment:DialogFragment() {
        private val crimeDetailViewModel:CrimeDetailViewModel by activityViewModels()//1设置为共享viewmodel
    
        override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
            super.onCreateDialog(savedInstanceState)
            val dateListener = DatePickerDialog.OnDateSetListener{
                    _, year, month, dayOfMonth ->
                val chooseDate: Date = GregorianCalendar(year, month, dayOfMonth).time//
                val crime = crimeDetailViewModel.crimeLiveData.value
                crime?.date = chooseDate
                crimeDetailViewModel.saveCrime(crime!!)//2保存
            }
            val calendar = Calendar.getInstance()
            calendar.time = crimeDetailViewModel.crimeLiveData.value?.date ?: Date()//
            val initYear = calendar.get(Calendar.YEAR)
            val initMonth = calendar.get(Calendar.MONTH)
            val initDay = calendar.get(Calendar.DAY_OF_MONTH)
    
            return DatePickerDialog(
                requireContext(),
                dateListener,
                initYear,
                initMonth,
                initDay
            )
        }
    }

    上面的代码实例中就使用了共享viewmodel.当然在另一个activity中也是用 by activityViewModels()这种方式初始化。

    配合Navigation和livedata使用简直不要太丝滑!!!

    bk