The problem I have seems to be quite weird.
In words
I have an app with a bottom navigation menu with 3 buttons, 3 fragments for each button and one MainActivity. When navigating to any of those fragments everything works as expected. The problem arises when I navigate to another fragment (let's call it fragment 4 or fr4) from any of those 3 fragments. Say I'm in fr1, I have a button that takes me to fr4. When I go back to fr1 (either using the android back button or by pressing the bottom bar button for fr1) then every thing that I do in the main activity or any of the 3 fragments is repeated 2 times. If I then go to fr4 again, and then back to fr1, then everything is repeated 3 times and so on.
In the code below fr1 is fragment_home and fr4 is fragment_profile.
Code
MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var navView: BottomNavigationView
private lateinit var binding: ActivityMainBinding
private val sharedViewModel: SharedViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
navView = binding.navView
val navController = findNavController(R.id.nav_host_fragment_activity_main)
navView.setupWithNavController(navController)
}
override fun onStart() {
super.onStart()
Timber.i("onStart main activity")
}
override fun onStop() {
super.onStop()
Timber.i("onStop main activity")
}
}
framgnet1.kt
class HomeFragment : Fragment() {
private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!
private val sharedViewModel: SharedViewModel by activityViewModels()
private val homeViewModel: HomeViewModel by viewModels()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
val root: View = binding.root
binding.lifecycleOwner = viewLifecycleOwner
binding.sharedViewModel = sharedViewModel
binding.homeViewModel = homeViewModel
binding.historyButton.setOnClickListener{
Timber.i("profile button clicked")
}
binding.profileButton.setOnClickListener { view ->
profileButtonClicked(view)
}
return root
}
fun profileButtonClicked() {
Timber.i("profile button clicked")
val action = HomeFragmentDirections.homeToProfileAction()
NavHostFragment.findNavController(this).navigate(action)
}
}
mobile_navigation.xml
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@ id/mobile_navigation"
app:startDestination="@ id/navigation_home">
<fragment
android:id="@ id/navigation_home"
android:name="com.comp.comp.ui.home.HomeFragment"
android:label="@string/title_home"
tools:layout="@layout/fragment_home">
<action
android:id="@ id/home_to_profile_action"
app:destination="@id/fragment_profile"
app:launchSingleTop="true" />
</fragment>
<fragment
android:id="@ id/navigation_dashboard"
android:name="com.comp.comp.ui.dashboard.DashboardFragment"
android:label="@string/title_dashboard"
tools:layout="@layout/fragment_dashboard" >
</fragment>
<fragment
android:id="@ id/navigation_notifications"
android:name="com.comp.comp.ui.notifications.NotificationsFragment"
android:label="@string/title_notifications"
tools:layout="@layout/fragment_notifications" />
<fragment
android:id="@ id/fragment_profile"
android:name="com.comp.comp.fragment_profile"
android:label="fragment_profile"
tools:layout="@layout/fragment_profile" />
</navigation>
I've tried toggling launchSingleTop="true"
on the navigation action to no avail.
What happens is the following:
- In the home fragment if I press the history button it prints "profile button clicked" once
- If I then tap the profile button, the app navigates to the profile fragment
- I go back to the home fragment either using the back button or pressing the home button on the bottom bar
- If I now press the history button "profile button clicked" is printed twice.
If I repeat the steps above then next time I press history button it will print "profile button clicked" 3 times and so on.
I've also tested to go to another activity, the onStop()
method in my main activity runs twice as well if I have been to the profile page once before. Same when I go back to the main activity the onStart()
method runs two times. Everything I do would run 2 times (or more) depending on how many times I go to the profile page. It looks like it created a main activity every time I visit the profile page that are alive at the same time. Any ideas why?
CodePudding user response:
I tried everything to no avail. Then I realised that at every configuration change it would plant a new Jake Wharton's Timber debug tree and it was logging everything for as many trees there were. Hope this can help someone. My mistake was the the Timber planing was in onCreate of the MainActivity, while it should be in the OnCreate of the Application.