简体   繁体   中英

Replace, add, replace fragment, then the Navigation Back button not working for first fragment

I have a fragment stack, where I use replace and add together. The code (in my activity) to add or replace my fragment as below

private fun addFragment(fragment: Fragment, name: String) {
    supportFragmentManager.beginTransaction().add(R.id.container, fragment)
            .addToBackStack(name).commit()
}

private fun replaceFragment(fragment: Fragment, name: String) {
    supportFragmentManager.beginTransaction().replace(R.id.container, fragment)
            .addToBackStack(name).commit()
}

In my fragment, I do have a toolbar with a back-icon for home menu. Upon clicking, it should help pop up my fragment to the previous stack.

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    toolbar_actionbar.setNavigationIcon(R.drawable.ic_arrow_back_black_24dp)
    setHasOptionsMenu(true)
    (activity as AppCompatActivity).setSupportActionBar(toolbar_actionbar)
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return if (item.itemId == android.R.id.home) {
        activity?.onBackPressed()
        true
    } else {
        super.onOptionsItemSelected(item)
    }
}

Just to be clear, I show activity onBackPressed is coded as below

override fun onBackPressed() {
    if (supportFragmentManager.backStackEntryCount > 0) {
        supportFragmentManager.popBackStackImmediate()
    } else {
        super.onBackPressed()
    }
}

Now if I add fragment1, add fragment2, add fragment3, add fragment4, and then press back, back, back, back... all works fine.

Similarly, if I replace with fragment1, replace with fragment2, replace with fragment3, replace with fragment4, and then back, back, back, back, all works fine.

However if I do, replace with fragment 1, add fragment 2, and replace with fragment 3, then press back, back, back.... The third time press back no longer works. Why??

To illustrate this better, I have put my code in github as below https://github.com/elye/issue_android_fragment_replace_add_replace

And recorded into a gif below (63 seconds gif) that show, the 4 adds works, 4 replaces works, but the mix of replace and add, will cause the toolbar back button not functioning after few backs.

Note the add fragment shows overlap number as the background is transparent. This is purposely done to easily distinguish add vs replace.

在此处输入图片说明

I suspect it's a google bug, but thought should share in case I miss anything important.

After investigation, it does seems like the issue are as describe below.

As each fragment would have it's own action bar set (in this stackoverflow, I simplify it to only R.id.home click for easier illustration of the issue). Each will call the below code when the fragment is added/removed.

(activity as AppCompatActivity).setSupportActionBar(toolbar_actionbar)

When we do add-add-replace (or replace-add-replace).... We have 3 fragments in backstack, but only one visible. Because the last replace, will remove the earlier 2 fragment.

When we click back button, the last replaced fragment will be pop out, and the system then restore the first 2 fragments.

During restoration of the first 2 fragments, the below code get called for both fragments in a short interval

(activity as AppCompatActivity).setSupportActionBar(toolbar_actionbar)

Some how I suspected this cause some behavior where the toolbar of the first fragment was not set fully (the Android SDK bug?).

In order to workaround the issue, when we pop the 2 fragment again, we have to force the 1st fragment to call

(activity as AppCompatActivity).setSupportActionBar(toolbar_actionbar)

With that my workaround for the above issue is to have that code above in onResume().

override fun onResume() {
    super.onResume()
    (activity as AppCompatActivity).setSupportActionBar(toolbar_actionbar)
}

And whenever a fragment backstack change, I will call the top fragment's onResume

    supportFragmentManager.addOnBackStackChangedListener {
        val currentFragment = supportFragmentManager.findFragmentById(R.id.container)
        currentFragment?.onResume()
    }

This now help to ensure regardless of replace-add mixture of stack, the toolbar menu will continue to work.

I have the sample workaround code in https://github.com/elye/issue_android_fragment_replace_add_replace_workaround

This is really a workaround than a solution. I hope some better answer posted, or if this is really a Google Bug, a fix could be done to it in later SDK release.

Try with this

if (supportFragmentManager.backStackEntryCount > 1) {
        supportFragmentManager.popBackStackImmediate()
    } else {
        super.onBackPressed()
    }

Hi put your toolbar code and it's xml part into MainActivity and it's relevent layout and remove from all fargment and it's layout. And put code like below:

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        toolbar_actionbar.setNavigationIcon(R.drawable.ic_arrow_back_black_24dp)
        setSupportActionBar(toolbar_actionbar)
}

And below code into MainActivity to solved it.

override fun onOptionsItemSelected(item: MenuItem): Boolean {
        return if (item.itemId == android.R.id.home) {
            if (supportFragmentManager.backStackEntryCount > 0) {
                supportFragmentManager.popBackStackImmediate()
            } else {
                super.onBackPressed()
            }
            true
        } else {
            super.onOptionsItemSelected(item)
        }
    }

I already tested and working perfectly. hope it helps you. if you have any doubt please comment/message into below i will explain you and solved your problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM