Android Primary/Detail Flow 模板的 fragment 点击跳转逻辑

更新日期: 2022-11-10 阅读次数: 213 字数: 408 分类: Android

TODO

  • 看懂原有 primary/detail 模板的跳转逻辑
  • 新建 snippet

list fragment

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    val itemDetailFragmentContainer: View? = view.findViewById(R.id.item_detail_nav_container)
    setupRecyclerView(recyclerView, itemDetailFragmentContainer)
}

private fun setupRecyclerView(
    recyclerView: RecyclerView,
    itemDetailFragmentContainer: View?
) {
    recyclerView.adapter = SimpleItemRecyclerViewAdapter(
        PlaceholderContent.ITEMS, itemDetailFragmentContainer
    )
}

但是这个 item_detail_nav_container 只存在于 sw600dp 的 layout 文件中:

> grep item_detail_nav_container -r app/
app/src/main/res/layout-sw600dp/fragment_item_list.xml:        android:id="@+id/item_detail_nav_container"

为何在手机上运行不报错呢?

recycler view adapter

class SimpleItemRecyclerViewAdapter(
        private val values: List<PlaceholderContent.PlaceholderItem>,
        private val itemDetailFragmentContainer: View?
) :
    RecyclerView.Adapter<SimpleItemRecyclerViewAdapter.ViewHolder>() {
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val item = values[position]
        holder.idView.text = item.id
        holder.contentView.text = item.content

        with(holder.itemView) {
            tag = item
            setOnClickListener { itemView ->
                val item = itemView.tag as PlaceholderContent.PlaceholderItem
                // Bundle: A mapping from String keys to various Parcelable values.
                // A Bundle is very much like a Java Map object that maps String keys to values.
                // The reason Android doesn't use plain old Map objects for this is that Map is too flexible;
                // it can contain objects (such as, say, I/O streams) that cannot be serialized.
                // The Bundle API restricts the types of objects that can be added to a bundle
                // in such a way that the bundle's contents are guaranteed to be serializable.
                // The Android framework relies on this property.
                val bundle = Bundle()
                bundle.putString(
                    ItemDetailFragment.ARG_ITEM_ID,
                    item.id
                )
                if (itemDetailFragmentContainer != null) {
                    itemDetailFragmentContainer.findNavController()
                        .navigate(R.id.fragment_item_detail, bundle)
                } else {
                    // 为何不都使用这个逻辑呢?
                    // 实际测试也确实没有问题
                    itemView.findNavController().navigate(R.id.show_item_detail, bundle)
                }
            }
            ...
        }
    }
}

show_item_detail 的定义:

> grep show_item_detail -r app/
app/src/main/res/navigation/primary_details_nav_graph.xml:            android:id="@+id/show_item_detail"

<fragment
    android:id="@+id/item_list_fragment"
    android:name="com.sunzhongwei.ble.ItemListFragment"
    android:label="ItemListFragment">
    <action
        android:id="@+id/show_item_detail"
        app:destination="@id/item_detail_fragment" />
</fragment>

detail fragment

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // public final android.os.Bundle getArguments()
    // Return the arguments supplied when the fragment was instantiated, if any.
    arguments?.let {
        if (it.containsKey(ARG_ITEM_ID)) {
            // Load the placeholder content specified by the fragment
            // arguments. In a real-world scenario, use a Loader
            // to load content from a content provider.
            item = PlaceholderContent.ITEM_MAP[it.getString(ARG_ITEM_ID)]
        }
    }
}

activity

override fun onCreate(savedInstanceState: Bundle?) {
    val navHostFragment =
        supportFragmentManager.findFragmentById(R.id.nav_host_fragment_item_detail) as NavHostFragment
    val navController = navHostFragment.navController
    appBarConfiguration = AppBarConfiguration(navController.graph)
    setupActionBarWithNavController(navController, appBarConfiguration)
}

爱评论不评论