“This is the 16th day of my participation in the First Challenge 2022. For details: First Challenge 2022”

I’m going to build a browser from scratch in 2022. I don’t have a name yet.

Since it is a browser, according to the international principle to achieve a multi-window function

I’m going to use ViewPager+Fragment to do this, but if you think about it, the disadvantage is obvious. Because to ensure that the Fragment does not destroy and rebuild, when there are too many fragments in the ViewPager, it will cause obvious lag

In multiple Windows, each window has its own return stack and each return stack has its own fragmentManager, so a UI-less Fragment is used as a carrier for the return stack


/ * * *@author huangweiliang
 */
class NavHostFragment(var name: String, var windowIndex: Int): Fragment() {
    private lateinit var binding: FragmentNavHostBinding
    private val TAG: String = "NavHostFragment"
    var curSelectFragment: Fragment? = null
    var curChildFragmentManager: FragmentManager? = null

    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        // Click the return button to process the Fragment of the current stack
        requireActivity().onBackPressedDispatcher.addCallback(this.object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed(a) {
                isEnabled = childFragmentManager.backStackEntryCount > 0
                if (isEnabled) childFragmentManager.popBackStackImmediate()
// else requireActivity().onBackPressedDispatcher.onBackPressed()
                else requireActivity().finish()
            }
        })
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup? , savedInstanceState:Bundle?).: View? {
        val view = inflater.inflate(R.layout.fragment_nav_host, container, false)
        binding = FragmentNavHostBinding.bind(view)
        return view
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?). {
        super.onViewCreated(view, savedInstanceState)
        var tag = name
        // Create the first page of the window, i.e. the home page Fragment
        if (childFragmentManager.findFragmentByTag(tag) == null) {

            // childFragmentManager is used here
            childFragmentManager.commitNow {
                val multiChildFragment = MultiChildFragment(name, 1.this@NavHostFragment)
                add(R.id.content, multiChildFragment, tag) // Replace cannot be used, otherwise it will be rebuilt each time you return
            }
        }
        Log.i(TAG, "$name: onViewCreated")}override fun onStart(a) {
        super.onStart()
        Log.i(TAG, "$name: onStart")}override fun onResume(a) {
        super.onResume()
        Log.i(TAG, "$name: onResume")}override fun onPause(a) {
        super.onPause()
        Log.i(TAG, "$name: onPause")}override fun onDestroy(a) {
        super.onDestroy()
        Log.i(TAG, "$name: onDestroy")}}Copy the code

FragmentNavHostBinding

<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/content"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
</androidx.fragment.app.FragmentContainerView>
Copy the code

Put an EditView on the search page for now


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

    <EditText
        android:id="@+id/ed_search"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="166dp"
        android:layout_marginEnd="16dp"
        android:padding="12dp"
        android:background="@drawable/gray_rounded_shape"
        android:drawableLeft="@drawable/ic_search_gray_24dp"

        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Copy the code

/ * * *@author huangweiliang
 * @date2021/12/9 * Multi-window, showing each Fragment */
class MultiChildFragment(var name: String, var depth: Int.var hostFragment: Fragment) : Fragment() {
    private lateinit var binding: FragmentMultiChildBinding
    val TAG = "MultiChildFragment"

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup? , savedInstanceState:Bundle?).: View? {

        Log.i(TAG, "$name-$depth: onCreateView")
        val view = inflater.inflate(R.layout.fragment_multi_child, container, false)
        binding = FragmentMultiChildBinding.bind(view)
        // Do a simple pass-through to display the current page
        binding.edSearch.text.append("$name-$depth")
        init(a)return view
    }

    private fun init(a){}override fun onViewCreated(view: View, savedInstanceState: Bundle?). {
        super.onViewCreated(view, savedInstanceState)
        Log.i(TAG, "$name-$depth: onViewCreated")}}Copy the code

Write a MultiStackParentFragment containing multiple return stacks

class MultiStackParentFragment: Fragment() {
    companion object {
        fun newInstance(a) = MultiStackParentFragment()
    }

    private lateinit var binding: FragmentMultiStackParentBinding
    private var windowNum: Int = 0
    /** * The current window Index */
    private var curWindowIndex: Int = 0
    /** * Records all window objects created */
    private val mStackList = ArrayList<NavHostFragment>()
    /** * returns the stack order, the storage returns the stack ID */
    private val mOrderStack = ArrayDeque<Int> ()override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)

    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup? , savedInstanceState:Bundle?).: View? {
        val view = inflater.inflate(R.layout.fragment_multi_stack_parent, container, false)
        binding = FragmentMultiStackParentBinding.bind(view)
        init(a)return view
    }

    private fun init(a){}}Copy the code

Add Windows inside. ChildFragmentManager manages all child Fragments that have that Fragment as their parent

private fun addWindow(a) {
    childFragmentManager.commitNow {
        //NavHostFragment represents a window object
        val navHostFragment = NavHostFragment("Window${++windowNum}", windowNum)
        curWindowIndex = windowNum
        mStackList.add(navHostFragment)
        add(R.id.content_fragment, navHostFragment) // Add window

    }
    transWindowIndex(curWindowIndex)
}
Copy the code

rendering