在 Android 的导航架构组件中将复杂对象作为参数传递

Passing complex objects as a parameter in Android's Navigation Architecture Component

我一直在寻找一些时间来 android 构建组件,最近在寻找导航组件。

我正在尝试将对象作为参数传递,以便下一个片段可以检索该数据,但为此我需要执行以下两项操作之一:

  1. 通过 Bundle 传递它,这将使我实现该对象的 Parcelable 接口。
  2. 使用我试过的 "Safeargs" 插件,它看起来在幕后使用了 Bundle 并且无论如何都需要实现 Parcelable 接口。

关于这些选项的事情是我读过 Parcelable 使用反射并且它在时间方面可能会变得非常昂贵


我也尝试构建一个 "SharedMasterDetailsViewModel" 但没有成功,因为可观察的回调没有在我新创建的片段上执行。 (我认为 LiveData 在创建片段之前执行回调)

这是一些关于我如何尝试解决这个问题的代码

SharedSessionViewModel

class SessionSharedViewModel : ViewModel() {


    var sharedSession: LiveData<Session> = MutableLiveData()
        private set

    fun setSession(data: Session) {
        val casted = this.sharedSession as MutableLiveData<Session>
        casted.postValue(data)
    }
}

MasterFragment

override fun onItemClicked(item: Session) {
    sessionSharedViewModel.setSession(item) // Item is a complex object of mine
    this@HomeFragment.findNavController().navigate(R.id.sessionDetailsFragment)
}

DetailsFragment

class SessionDetailsFragment : Fragment() {

    companion object {
        fun newInstance() = SessionDetailsFragment()
    }

    private lateinit var sharedViewModel: SessionSharedViewModel

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.session_details_fragment, container, false)
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        Log.d("SESSIONDETAILS","created!")

        super.onActivityCreated(savedInstanceState)
        sharedViewModel = ViewModelProviders.of(this).get(SessionSharedViewModel::class.java)
        sharedViewModel.sharedSession.observe({this.lifecycle},{ handleUI(it!!)})
    }

    fun handleUI(sharedSession: Session) {
        Toast.makeText(activity, "This is inside new activity: ${sharedSession.title()}", Toast.LENGTH_SHORT)
    }
}

我最后的希望是将我的对象序列化为 JSON 字符串并在我的 Detail 片段的 onCreateActivity lyfecycle 挂钩上重新解析该对象,但我觉得这不是正确的解决方案。

在最坏的情况下,我只会传递对象的 ID 并从网络中重新获取它,但由于我已经有了要显示的信息,所以我想将其作为参数传递。

TL;博士

你不能。

实际解释

第一件事;以下声明

The thing about these options is that I've read that Parcelable makes use of reflection and it can get quite expensive regarding time.

是个谎言

由于您实现了 Parcelable,您只是提供了有关如何使用基本原始类型进行序列化和反序列化的方法:IE:writeBytesreadBytesreadIntwriteInt

Parcelable 不使用反射。 Serializable 有!

虽然您确实被迫使用 Parcelable jet brains 开发了一个非常有用的注释,它消除了必须编写名为 @Parcelize.

的 parcelable 实现的痛苦

示例用法:

@Parcelize
data class User(val username: String, val password: String) : Parcelable

现在您无需编写一行 Parcelable 实现即可传递 class 的实例。

更多信息here