1

I have a bottom nav with 4 fragments Home, Following, Notification, and Profile, there is no issue with the bottom navigation on backstack , but now for eg from profile fragment I jumped to a fragment called edit_profile which is not a part of the bottom nav and when press back I want that it should go back to the profile fragment but the backstack is taking me from edit_profile to directly home fragment

here is a recording link

I recently change my project from java to kotlin and I'm a beginner in kotlin

i really like the navigation of Pinterest and Instagram

Note:- All this code is automatically changed to kotlin (with some changes done manually ) , this issue was also with java and not after migrating to kotlin , Also if you want more reference of the code please tell me i will update the question

Code

MainActivity.kt // Bottom Nav

class MainActivity : AppCompatActivity() {
    var bottomNavigationView: BottomNavigationView? = null
    var integerDeque: Deque<Int> = ArrayDeque(3)
    var flag = true

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
        setContentView(R.layout.activity_main)
        val window = this.window
        window.statusBarColor = this.resources.getColor(R.color.black)
        bottomNavigationView = findViewById(R.id.bottom_navigation_view)
        integerDeque.push(R.id.nav_home)
        loadFragments(Home_Fragment())
        bottomNavigationView!!.selectedItemId = R.id.nav_home
        bottomNavigationView!!.setOnNavigationItemSelectedListener(
            BottomNavigationView.OnNavigationItemSelectedListener { item: MenuItem ->
                val id = item.itemId
                if (integerDeque.contains(id)) {
                    if (id == R.id.nav_home) {
                        integerDeque.size
                        if (flag) {
                            integerDeque.addFirst(R.id.nav_home)
                            flag = false
                        }
                    }
                    integerDeque.remove(id)
                }
                integerDeque.push(id)
                loadFragments(getFragment(item.itemId))
                false
            }
        )
    }

    @SuppressLint("NonConstantResourceId")
    private fun getFragment(itemId: Int): Fragment {
        when (itemId) {
            R.id.nav_home -> {
                bottomNavigationView!!.menu.getItem(0).isChecked = true
                return Home_Fragment()
            }
            R.id.nav_following -> {
                bottomNavigationView!!.menu.getItem(1).isChecked = true
                return Following_Fragment()
            }
            R.id.nav_notification -> {
                bottomNavigationView!!.menu.getItem(2).isChecked = true
                return Notification_Fragment()
            }
            R.id.nav_profile -> {
                bottomNavigationView!!.menu.getItem(3).isChecked = true
                return Profile_Fragment()
            }
        }
        bottomNavigationView!!.menu.getItem(0).isChecked = true
        return Home_Fragment()
    }

    private fun loadFragments(fragment: Fragment?) {
        if (fragment != null) {
            supportFragmentManager.beginTransaction()
                .replace(R.id.fragment_container, fragment, fragment.javaClass.simpleName)
                .commit()
        }
    }

    override fun onBackPressed() {
        integerDeque.pop()
        if (!integerDeque.isEmpty()) {
            loadFragments(getFragment(integerDeque.peek()))
        } else {
            finish()
        }
    }

Edit_Profile.kt // from this fragment i want to go back to the last fragment which should be the profile fragment

class Edit_Profile : Fragment() {
    private var profilePhoto: CircleImageView? = null
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = inflater.inflate(R.layout.fragment_edit_profile, container, false)
        profilePhoto = view.findViewById(R.id.circleImageView)
        initImageLoader()
        setProfileImage()
        val imageView = view.findViewById<ImageView>(R.id.backArrow)
        imageView.setOnClickListener {
            val newCase: Fragment = Profile_Fragment()
            assert(fragmentManager != null)
            val transaction = requireFragmentManager().beginTransaction()
            transaction.replace(R.id.fragment_container, newCase)
            transaction.addToBackStack(Profile_Fragment.toString())
            transaction.commit()
        }
        return view
    }

Edit

added a part of the transaction from Profile Fragment to Edit Profile

ProfileFragment.kt

editProfileButton!!.setOnClickListener(View.OnClickListener { v: View? ->
            val edit_profile: Fragment = Edit_Profile()
            requireActivity().getSupportFragmentManager()
                .beginTransaction()
                .add(R.id.fragment_container, edit_profile,"TAG")
                .addToBackStack("TAG")
                .commit()
        })
4
  • My guess is replace can be the issue as it means clearing all fragments and then adding new, Instead try adding the fragment and not replacing. Commented Jan 13, 2022 at 9:41
  • hey I'm new to kotlin , can you tell me is there an easy way to manage backstack navigation (i really like the navigation of Pinterest and Instagram) Commented Jan 13, 2022 at 9:53
  • How you did the transaction to Edit_Profile fragment? Commented Feb 13, 2022 at 21:38
  • @Zain i have added the code in Edit section please check to know how do i done the transaction Commented Feb 14, 2022 at 4:16

2 Answers 2

1
+50

Now you are managing the back stack through the integerDeque array.

  • When you go to a new BottomNavigationView fragment; you added its id to the array if it doesn't already exist.
  • When you pop up the back stack; the fragment at the top is kicked off the array.

But since you pushed all those ids in the bottomNavigationView.setOnItemSelectedListener callback; then the integerDeque array only contains BottomNavigationView fragments ids.

And as the Edit_Profile fragment is not a part of BottomNavigationView fragments, then it won't be added/popped off the queue. Instead when you try to popup the back stack whenever the Edit_Profile fragment is shown; the normal behavior you manage in the onBackPressed() continues and the Profile_Fragment id will pop up from the queue making you return to the preceding fragment (Home_Fragment) in your mentioned example.

A little fix to this is to consider adding an id into the queue when you transact to Edit_Profile fragment so that this id is popped off the queue resulting in back to Profile_Fragment fragment.

You can do that with the fragment's id in order to make sure it's unique:

editProfileButton!!.setOnClickListener(View.OnClickListener { v: View? ->
        val edit_profile: Fragment = Edit_Profile()
        requireActivity().getSupportFragmentManager()
            .beginTransaction()
            .add(R.id.fragment_container, edit_profile,"TAG")
            .addToBackStack("TAG")
            .commit()
            
        (requireActivity() as MainActivity).integerDeque.push(id) // <<<< pushing id to the queue
        
    })

This should fix your problem.


Side tips:

  • Use setOnItemSelectedListener instead of setOnNavigationItemSelectedListener on the BNV as the latter is deprecated.
  • Return true instead of false from setOnItemSelectedListener callback as this should consume the event and mark the BNV as selected.
  • In Edit_Profile transaction replace the fragment instead of adding it with add as already the container is consumed; and this would make you avoid overlapping fragments in the container.
  • In onBackPressed(); you'd replace loadFragments(..) with bottomNavigationView.selectedItemId = integerDeque.peek(); this could be lighter to reuse the same fragment instead of redoing the transaction.
Sign up to request clarification or add additional context in comments.

3 Comments

Thank You Soooooo Much brother I was stuck on this issue from last 3 months , i asked this question so many times on SO and there are answers to it but didn't solved my issue , but this one line solved the issue , thank you once again
hello, I'm trying to add this kotlin line into a new project which is in java but don't know what should be in java this is the kotlin line " bottomNavigationView!!.selectedItemId = integerDeque.peek(); " can you help me with this
@VasantRaval HYG bottomNavigationView.setSelectedItemId(integerDeque.peek());
1

Usually I follow this pattern enter image description here

Where I add HomeF in main container which includes all bottom nav tab, and all bottom nav tab will open in home container, and those fragment which are not part of bottom nav will open in main container. I generally add(not replace) all the fragments in main container and set add to back stack , so that if user goes from profile (home_container) to something in main container , while backstack we can pop the top fragment and user will be seeing profile.

7 Comments

I have a fragment container if you are talking about it
Are you using same fragment_container to add and replace the fragments
Ok then I would suggest to follow above design for adding fragments.
Checkout this it will help you understand even more stackoverflow.com/a/62354505/12971639
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.