在使用 NavigationDrawer 导航时,Android Navigation 组件存在延迟问题。

24
我正在将我的应用程序更新为导航架构组件,我发现它在替换片段时有延迟,这在导航抽屉中是可见的,导航抽屉不能平滑地关闭。
到目前为止,我一直遵循这种方法:

https://vikrammnit.wordpress.com/2016/03/28/facing-navigation-drawer-item-onclick-lag/

所以我在onDrawerClosed中导航,而不是在onNavigationItemSelected中,以避免故障。
这是一个非常普遍的问题,但它又回来了。使用导航组件,它又变得卡顿了,我看不到在onDrawerClosed中实现它的方法。
以下是一些旧的答案,先前还没有使用导航组件: 导航抽屉在Android上卡顿 DrawerLayout的项目点击-何时替换片段为正确时间? 非常感谢。

1
不幸的是,我遇到了同样的问题。我想到的唯一解决方法是让Fragment在加载其内容之前等待一会儿,但这远非理想。我希望有更好的解决办法... - Mauker
你能公开代码和XML吗? - Cuong Nguyen
我不知道2019年的情况如何,但使用Navigation版本2.4.1,您可以覆盖onDrawerClosed并使用NavController类和.navigate(..)方法来放置片段导航逻辑。这是我所知道的全部内容。 - Michael Zur
2个回答

7
我在撰写此答案时正在解决此问题。经过一些测试,我得出结论:在创建片段后的片段中执行的代码(例如初始化RecyclerView适配器并用数据填充它,或配置UI)会导致抽屉延迟,因为所有这些都是同时发生的。
现在我得到的最好的想法与一些旧的解决方案类似,依赖于onDrawerClosed。我们将延迟片段中的代码执行,直到抽屉关闭。片段的布局将在抽屉关闭之前可见,因此它仍将看起来快速和响应。
请注意,我还使用了导航组件。
首先,我们将创建一个接口并在片段中实现它。
interface StartFragmentListener {
    fun configureFragment()
}

在活动设置DrawerListener时,像这样:
private fun configureDrawerStateListener(){
    psMainNavDrawerLayout.addDrawerListener(object: DrawerLayout.DrawerListener{
        override fun onDrawerStateChanged(newState: Int) {}
        override fun onDrawerSlide(drawerView: View, slideOffset: Float) {}
        override fun onDrawerOpened(drawerView: View) {}

        override fun onDrawerClosed(drawerView: View) {
            notifyDrawerClosed()
        }

    })
}

通知片段抽屉已关闭,可以执行引起延迟的操作:
private fun notifyDrawerClosed(){
    val currentFragment =
            supportFragmentManager.findFragmentById(R.id.psMainNavHostFragment)
                    ?.childFragmentManager?.primaryNavigationFragment

    if(currentFragment is StartFragmentListenr && currentFragment != null)
        currentFragment.configureFragment()

}

如果您不是从抽屉导航到片段(例如按下返回按钮)中,您还需要通知片段执行其任务。我们将实现FragmentLifecycleCallbacksListener:

private fun setupFragmentLifecycleCallbacksListener(){
    supportFragmentManager.findFragmentById(R.id.psMainNavHostFragment)
            ?.childFragmentManager?.registerFragmentLifecycleCallbacks(object : FragmentManager.FragmentLifecycleCallbacks() {

        override fun onFragmentActivityCreated(fm: FragmentManager, f: Fragment, savedInstanceState: Bundle?) {
            super.onFragmentActivityCreated(fm, f, savedInstanceState)

            if (!psMainNavDrawerLayout.isDrawerOpen(GravityCompat.START)) {
                if (f is StartFragmentListener)
                    f.configureFragment()
            }

        }
    }, true)
}

在片段中:

class MyFragment: Fragment(), MyActivity.StartFragmentListener {
    private var shouldConfigureUI = true
    ...

    override fun onDetach() {
        super.onDetach()
        shouldConfigureUI = true
    }

    override fun configureFragment() {
        if(shouldConfigureUI){
            shouldConfigureUI = false
            //do your things here, like configuring UI, getting data from VM etc...
            configureUI()
        }
    }
} 

可以通过共享视图模型来实现类似的解决方案。


1
不,这个解决方案可以处理它。 BackStackListener 将在主 Fragment 中注册每个 Fragment 更改,但仅当在更改 Fragment 时抽屉关闭时才会调用 configureFragment() - 表示我们在抽屉外导航到该 Fragment。 - UrosKekovic
1
啊!你说得对。太棒了 :) 好主意。我今天会测试它。 - Mauker
1
我已经测试了你的解决方案,哇,性能有了巨大的提升,谢谢!至于潜在的错误,一个标志位可能可以解决问题,但我也不确定它是否真的会发生。 - Mauker
1
@Mauker,必须完成,我错过了。我现在会更新它,谢谢。 - UrosKekovic
当您点击抽屉外部时,抽屉会关闭。但是我希望在选择项目时抽屉能够平稳地关闭。我通过在onViewCreated中添加shouldConfigureUI = true,在配置UI后添加shouldConfigureUI = false来解决了这个问题。 - Patriotic
显示剩余7条评论

0
避免在 Android 的 onNavigationItemSelected 更改 Fragment / Activity 时引起的延迟。
导航抽屉是应用程序中最常见的选项,当我们有五个以上的选项时,我们会转向导航菜单。
我在许多应用程序中看到,当我们从导航菜单更改选项时,我们观察到它会出现延迟,一些人在 StackOverflow 上建议使用像下面的 Handler:
private void openDrawerActivity(final Class className) {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                ProjectUtils.genericIntent(NewDrawer.this, className, null, false);
            }
        }, 200);
    }

但在上面的代码中,仍然不够流畅,我想为什么我们添加处理程序可能有另一种解决方案经过了这么多的研究和开发,我发现当抽屉将要关闭时,我们需要更改片段/活动。让我们看看实现。

有关详细解决方案的更多详细信息,请查看https://android.jlelse.eu/avoid-the-lag-caused-while-changing-fragment-activity-onnavigationitemselected-android-28bcb2528ad8。它确实很有帮助和有用。

希望您能在其中找到更好的解决方案!


这个问题涉及到导航组件库。 - Javier Delgado
有没有类似于onTransitionDone函数的东西,而不是使用postDelayed? - Roar Grønmo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接