Переход к фрагменту из действия и обратно к действию приводит к тому, что действие создается несколько раз

#android #kotlin #android-fragments #android-lifecycle #android-navigation

Вопрос:

Проблема, с которой я столкнулся, кажется довольно странной.

На словах

У меня есть приложение с нижним меню навигации с 3 кнопками, 3 фрагментами для каждой кнопки и одной основной активностью. При переходе к любому из этих фрагментов все работает так, как ожидалось. Проблема возникает, когда я перехожу к другому фрагменту (назовем его фрагментом 4 или fr4) из любого из этих 3 фрагментов. Скажем, я в fr1, у меня есть кнопка, которая переводит меня в fr4. Когда я возвращаюсь к fr1 (либо с помощью кнопки Android назад, либо нажав кнопку нижней панели для fr1), то все, что я делаю в основном действии или любом из 3 фрагментов, повторяется 2 раза. Если я затем снова перейду к fr4, а затем вернусь к fr1, то все повторится 3 раза и так далее.

В приведенном ниже коде fr1-это fragment_home, а fr4-это fragment_profile.

Код

Основная активность.тыс. т

 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>
 

Я попытался включить launchSingleTop="true" навигационное действие, но безрезультатно.

Происходит следующее:

  1. В домашнем фрагменте, если я нажму кнопку «История», он напечатает «кнопка профиля нажата» один раз
  2. Если затем я нажму кнопку профиля, приложение перейдет к фрагменту профиля
  3. Я возвращаюсь к главному фрагменту либо с помощью кнопки «Назад», либо нажатием кнопки «Домой» на нижней панели
  4. Если я сейчас нажму кнопку «История», «нажата кнопка профиля» будет напечатана дважды.

Если я повторю описанные выше действия, то в следующий раз, когда я нажму кнопку истории, она напечатает «нажата кнопка профиля» 3 раза и так далее.

Я также протестировал переход к другому виду деятельности, onStop() метод в моей основной деятельности работает в два раза лучше, если я уже был на странице профиля один раз. То же самое, когда я возвращаюсь к основному действию onStart() , метод выполняется два раза. Все, что я делаю, будет выполняться 2 раза (или более) в зависимости от того, сколько раз я захожу на страницу профиля. Похоже, что он создавал основное действие каждый раз, когда я посещаю страницу профиля, которая одновременно активна. Есть идеи, почему?

Ответ №1:

Я перепробовал все, но безрезультатно. Затем я понял, что при каждом изменении конфигурации он будет сажать новое дерево отладки древесины Джейка Уортона, и он регистрировал все, сколько деревьев было. Надеюсь, это кому-нибудь поможет. Моя ошибка заключалась в том, что строгание древесины было в onCreate основной активности, в то время как оно должно быть в onCreate приложения.