【问题标题】:Fragment continue recreates again when back pressed several times before app closes在应用程序关闭之前多次按下后,片段继续重新创建
【发布时间】:2022-11-01 17:29:39
【问题描述】:

我试图在我的应用程序中解决一个问题,当应用程序打开时,我有一个包含 7 个片段的导航抽屉,和/或如果我从详细信息活动返回,如果我点击后退按钮,我会看到片段再次重新创建,我不得不一次又一次地按下后退按钮来关闭应用程序

GIF中的问题

主要活动

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    var APP_START_TIME: Long = 0


    private lateinit var appBarConfiguration: AppBarConfiguration
    private var _binding: ActivityMainBinding? = null
    private val binding get() = _binding!!
    private lateinit var navController: NavController
    private lateinit var postViewModel: PostViewModel
    private var _navGraph: NavGraph? = null
    private val navGraph get() = _navGraph!!
    lateinit var adView: AdView
    private var adRequest: AdRequest? = null


    private val applicationScope = CoroutineScope(Dispatchers.Unconfined)


    override fun onDestroy() {
        super.onDestroy()

        adView.destroy()
        adRequest = null
        _binding = null
    }

    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)
        APP_START_TIME = System.currentTimeMillis()
        _binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)


        adView = AdView(this)
        delayedInit()
        postViewModel = ViewModelProvider(this)[PostViewModel::
        class.java]


        setSupportActionBar(binding.toolbar)


        val drawerLayout: DrawerLayout = binding.drawerLayout


        val navHostFragment =
            supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment?

        if (navHostFragment != null) {
            navController = navHostFragment.navController
        }




        appBarConfiguration = AppBarConfiguration(
            setOf(
                R.id.nav_home, R.id.nav_accessory,
                R.id.nav_arcade, R.id.nav_fashion,
                R.id.nav_food, R.id.nav_heath,
                R.id.nav_lifestyle, R.id.nav_sports, R.id.nav_favorites, R.id.settingsFragment
            ), drawerLayout
        )



        setupActionBarWithNavController(this, navController, appBarConfiguration)
        setupWithNavController(binding.navView, navController)

        _navGraph = navController.navInflater.inflate(R.navigation.mobile_navigation)


        onBackPressedDispatcher.addCallback(this /* lifecycle owner */,
            object : OnBackPressedCallback(true) {
                override fun handleOnBackPressed() {
                    // Back is pressed... Finishing the activity

                    finish()
                }
            })
}

//    override fun onStart() {
//        super.onStart()
//    }


    override fun onPause() {
        super.onPause()
        adView.pause()
    }

    override fun onResume() {
        super.onResume()
        adView.resume()

        postViewModel.currentDestination.observe(this) { currentDestination ->

            Log.w(TAG, "currentDestination: at first run is $currentDestination")

            navGraph.setStartDestination(currentDestination)
            navController.graph = navGraph


        }

        navController.addOnDestinationChangedListener { _, destination, _ ->
            Log.d(TAG, "addOnDestinationChangedListener: " + destination.id)

            if (destination.id != R.id.settingsFragment
                && destination.id != R.id.aboutFragment
                && destination.id != R.id.privacyPolicyFragment
            ) {
                postViewModel.saveCurrentDestination(destination.id)
            }

        }
    }

    private fun requestHomeBanner() {

        adRequest = Constants.callAndBuildAdRequest()
        adView.adListener = object : AdListener() {

            override fun onAdFailedToLoad(adError: LoadAdError) {
                Log.e(TAG, "onAdFailedToLoad: ${adError.cause.toString()}")
                Log.e(TAG, "onAdFailedToLoad: ${adError.responseInfo.toString()}")
            }

        }



        adRequest?.let { adView.loadAd(it) }


    }



    private fun delayedInit() = applicationScope.launch {
        binding.adViewContainer.addView(adView)
        adView.adUnitId = "ca-app-pub-3940256099942544/6300978111"
        adView.setAdSize(Constants.GET_AD_SIZE(this@MainActivity))


        val testDeviceIds = listOf("048DC5C3C06FBD17D9AD205151167F48")
        val configuration = RequestConfiguration.Builder().setTestDeviceIds(testDeviceIds).build()
        MobileAds.setRequestConfiguration(configuration)


        if (Utils.hasInternetConnection(this@MainActivity)) {
            requestTheLatestConsentInformation(this@MainActivity)
            MobileAds.initialize(this@MainActivity) {
                Log.d(TAG, "onInitCompleted")
            }

            requestHomeBanner()
        }
    }


    override fun onSupportNavigateUp(): Boolean {
        return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
    }

}

我的尝试解决

  1. 我尝试在OnBackPressedCallback 中添加以下代码
    navGraph.clear()
    binding.drawerLayout.removeAllViews()
    binding.navView.removeAllViews()
    
    1. 我还尝试在addOnDestinationChangedListener 中添加onBackPressedDispatcher 回调
                onBackPressedDispatcher.addCallback(this /* lifecycle owner */,
                  object : OnBackPressedCallback(true) {
                      override fun handleOnBackPressed() {
                          // Back is pressed... Finishing the activity
    
                         navController.clearBackStack(destination.id)
                          finish()
                     }
                   })
    
    1. 我尝试处理从片段本身而不是来自活动的后按,如下所示
    requireActivity()
                .onBackPressedDispatcher
                .addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) {
                    override fun handleOnBackPressed() {
                        Log.d(TAG, "Fragment back pressed invoked")
    
    //                    hideShimmerEffect()
                        // Do custom work here
                     
    
    
    
                        requireActivity().finish()
    
                  //       if you want onBackPressed() to be called as normal afterwards
                        if (isEnabled) {
                            isEnabled = false
                            requireActivity().onBackPressed()
                        }
                    }
                })
    
    1. 我试图通过在上面的代码中添加以下两行来弹出返回堆栈或清除它
    findNavController().popBackStack()
    findNavController().clearBackStack(R.id.nav_home)
    
    1. 最后我尝试编辑onSupportNavigateUp,如下所示
    
     override fun onSupportNavigateUp(): Boolean {
            return if(supportFragmentManager.backStackEntryCount > 0){
                navController.navigateUp(appBarConfiguration)
            }else {
                finish()
                super.onSupportNavigateUp()
    
            }
        }
    

    这是我最后一次编辑的代码,所有这些尝试都没有解决问题

【问题讨论】:

    标签: android kotlin android-fragments navigation-drawer onbackpressed


    【解决方案1】:

    如果您想返回初始活动或在单个活动应用程序的情况下退出应用程序添加

     android:noHistory="true" 
    

    在活动标签内的清单文件中

    【讨论】:

    • 这不是一个活动,我还有另一个活动详情活动显示项目详细信息
    【解决方案2】:

    尝试使用这个函数来启动你的片段:

    private fun loadFragment(fragment: Fragment?) {
            if (fragment != null) {
                val fragmentManager = supportFragmentManager
                fragmentManager
                    .beginTransaction()
                    .replace(R.id.nav_host_fragment, fragment)
                    .commit()
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-02
      • 2014-04-30
      • 1970-01-01
      • 1970-01-01
      • 2021-10-25
      相关资源
      最近更新 更多