当前位置: 首页 > 知识库问答 >
问题:

优化抽屉和活动启动速度

丁沛
2023-03-14

我正在使用谷歌抽屉布局。

当一个项目被点击时,抽屉被顺利关闭,并且会启动一个活动。将这些活动变成片段不是一个选项。正因为如此,启动一个活动然后关闭抽屉也不是一个选项。关闭抽屉和同时启动活动会使关闭动画结巴。

鉴于我想先顺利关闭它,然后启动活动,我对用户单击抽屉项目和他们看到他们想要去的活动之间的延迟存在问题。

这就是每个项目的单击侦听器的外观。

final View.OnClickListener mainItemClickListener = new View.OnClickListener() {
    @Override
    public void onClick(final View v) {
        mViewToLaunch = v;
        mDrawerLayout.closeDrawers();
    }
};

我的活动也是DrawerListener,它的onDrawerCloked方法如下所示:

@Override
public synchronized void onDrawerClosed(final View view) {
    if (mViewToLaunch != null) {
        onDrawerItemSelection(mViewToLaunch);
        mViewToLaunch = null;
    }
}

onDrawerItem选择只是启动五个活动之一。

我在抽屉的暂停上什么也不做。

我正在检测这个,从调用onClick的那一刻到onDrawerCloked结束的那一刻,平均需要500-650ms。

一旦抽屉关闭,在相应的活动启动之前,会有一个明显的滞后。

我意识到有几件事正在发生:

>

  • 结束动画发生,就在那里几毫秒(假设300)。

    然后在抽屉视觉关闭和侦听器被解雇之间可能会有一些延迟。我正试图通过查看DrawerLayout源代码来了解到底发生了多少这种情况,但还没有弄清楚。

    然后是启动的活动执行其启动生命周期方法所需的时间量,包括恢复。我还没有对此进行检测,但我估计约为200-300ms。

    这似乎是一个问题,走错了路会付出很大代价,所以我想确保我完全理解它。

    一个解决方案是跳过结束动画,但我希望保留它。

    如何尽可能减少过渡时间?

  • 共有3个答案

    宦烈
    2023-03-14

    所以我似乎用合理的解决方案解决了这个问题。

    可感知延迟的最大来源是抽屉视觉关闭和调用UndrawerClosed之间的延迟。我通过将一个可运行的处理程序发布到一个私有的处理程序来解决这个问题,该处理程序以指定的延迟启动预期的活动。选择该延迟与抽屉关闭相对应。

    我试图在80%的进度后启动onDrawerSlide,但这有两个问题。首先是口吃。第二个问题是,如果你将百分比增加到90%或95%,那么由于动画的性质,它根本不会被调用的可能性增加了——然后你不得不退回到绘图关闭,这违背了目的。

    这种解决方案可能会口吃,尤其是在较旧的手机上,但只要将延迟增加到足够高,这种可能性就可以降低到0。我认为250ms是口吃和潜伏期之间的合理平衡。

    代码的相关部分如下所示:

    public class DrawerActivity extends SherlockFragmentActivity {
        private final Handler mDrawerHandler = new Handler();
    
        private void scheduleLaunchAndCloseDrawer(final View v) {
            // Clears any previously posted runnables, for double clicks
            mDrawerHandler.removeCallbacksAndMessages(null); 
    
            mDrawerHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    onDrawerItemSelection(v);
                }
            }, 250);
            // The millisecond delay is arbitrary and was arrived at through trial and error
    
            mDrawerLayout.closeDrawer();
        }
    }
    
    林弘文
    2023-03-14

    我在抽屉布局方面也面临同样的问题。

    我对此进行了研究,然后找到了一个很好的解决方案。

    我正在做的是......

    如果您参考Android示例应用程序了解抽屉布局,请检查selectItem(position)的代码

    在此函数中,基于位置选择的片段被调用。我已经修改了以下代码根据我的需要,并没有动画关闭口吃良好的工作。

    private void selectItem(final int position) {
        //Toast.makeText(getApplicationContext(), "Clicked", Toast.LENGTH_SHORT).show();
        mDrawerLayout.closeDrawer(drawerMain);
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Fragment fragment = new TimelineFragment(UserTimeLineActivity.this);
                Bundle args = new Bundle();
                args.putInt(TimelineFragment.ARG_PLANET_NUMBER, position);
                fragment.setArguments(args);
    
                FragmentManager fragmentManager = getSupportFragmentManager();
                fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();
    
                // update selected item and title, then close the drawer
                mCategoryDrawerList.setItemChecked(position, true);
    
                setTitle("TimeLine: " + mCategolyTitles[position]);
            }
        }, 200);
    
    
        // update the main content by replacing fragments
    
    
    }
    

    在这里,我首先关闭抽屉布局。大约需要250毫秒。然后我的处理程序将调用片段。工作平稳,符合要求。

    希望它也能对你有所帮助。

    享受编码…:)

    耿俊
    2023-03-14

    根据文件,

    避免在动画期间执行昂贵的操作,例如布局,因为它会导致口吃;尝试在STATE_IDLE状态下执行昂贵的操作。

    您可以重写ActionBarDrawerTougle(它实现了DrawerLayout. DrawerListener)的onDrawerStateChanged方法,而不是使用Handler并对时间延迟进行硬编码,这样您就可以在抽屉完全关闭时执行昂贵的操作。

    在MainActivity内部,

    private class SmoothActionBarDrawerToggle extends ActionBarDrawerToggle {
    
        private Runnable runnable;
    
        public SmoothActionBarDrawerToggle(Activity activity, DrawerLayout drawerLayout, Toolbar toolbar, int openDrawerContentDescRes, int closeDrawerContentDescRes) {
            super(activity, drawerLayout, toolbar, openDrawerContentDescRes, closeDrawerContentDescRes);
        }
    
        @Override
        public void onDrawerOpened(View drawerView) {
            super.onDrawerOpened(drawerView);
            invalidateOptionsMenu();
        }
        @Override
        public void onDrawerClosed(View view) {
            super.onDrawerClosed(view);
            invalidateOptionsMenu();
        }
        @Override
        public void onDrawerStateChanged(int newState) {
            super.onDrawerStateChanged(newState);
            if (runnable != null && newState == DrawerLayout.STATE_IDLE) {
                runnable.run();
                runnable = null;
            }
        }
    
        public void runWhenIdle(Runnable runnable) {
            this.runnable = runnable;
        }
    }
    

    在onCreate中设置抽屉定位器:

    mDrawerToggle = new SmoothActionBarDrawerToggle(this, mDrawerLayout, mToolbar, R.string.open, R.string.close);
    mDrawerLayout.setDrawerListener(mDrawerToggle);
    

    最后

    private void selectItem(int position) {
        switch (position) {
            case DRAWER_ITEM_SETTINGS: {
                mDrawerToggle.runWhenIdle(new Runnable() {
                    @Override
                    public void run() {
                        Intent intent = new Intent(MainActivity.this, SettingsActivity.class);
                        startActivity(intent);
                    }
                });
                mDrawerLayout.closeDrawers();
                break;
            }
            case DRAWER_ITEM_HELP: {
                mDrawerToggle.runWhenIdle(new Runnable() {
                    @Override
                    public void run() {
                        Intent intent = new Intent(MainActivity.this, HelpActivity.class);
                        startActivity(intent);
                    }
                });
                mDrawerLayout.closeDrawers();
                break;
            }
        }
    }
    
     类似资料:
    • 我正在试用本教程中给出的导航抽屉(幻灯片菜单)。 上面的链接和我的不同之处在于,我试图调用活动而不是调用片段。当应用程序打开时,我无法看到导航抽屉菜单,我只能看到打开HOME活动的操作栏。 以下是我更改的代码:(是否需要一个片段,或者我可以在导航抽屉的第一个屏幕上使用活动?) 我如何解决这个问题,以便在我的家庭活动中显示导航抽屉? 更新: 我甚至尝试了以下链接中给出的选项: 如何使用导航抽屉调用我

    • 我是android新手。我想实现一个由项目列表组成的导航抽屉,单击它会打开一个新活动。基本上是所有活动的导航抽屉。当我从导航抽屉中选择一个项目时,特定的活动就会打开。导航抽屉代码是通过执行空活动来实现的。我想在所有活动中实现导航抽屉功能,这些活动被视为空活动,这些活动已经有了一些功能,导航抽屉功能也可以工作。请帮帮我。 这是activity_header档案 这是我的主要活动 这是头活动java代

    • 我正在尝试创建一个导航抽屉活动,这样我就可以扩展该活动,并按照这个问题链接中给出的答案在所有活动中使用菜单,但我的测试应用程序总是崩溃,下面是我的代码: BaseActivity.java

    • 这是我的登录活动,我有一个按钮进入MainActivity,它已经包含导航抽屉了 这是我的主要活动 我已经更改了AndroidManifest,使LoginActivity成为默认的开始活动,但当我单击按钮时,它不会进入MainActivity。 这就是错误所在 E/AndroidRuntime:致命异常:主进程:com。重大进展myapplication22,PID:11422 java。lan

    • 我有一个活动a,一个列表片段P和两个片段Q和R。 当应用程序启动时,会创建一个,加载P。根据用户点击的内容,它被Q或R取代。 现在,通过参考本教程,我实现了一个导航抽屉,向用户显示某些项目。然而,由于我在活动中实现了导航抽屉,它显示了所有片段。我希望它只对P可用。 (非常类似于谷歌Gmail应用程序。当用户在主屏幕上时,抽屉就出现了。当用户点击打开电子邮件时,抽屉就会切换到后退按钮) 我不知道如何

    • 问题内容: 有没有一种方法可以只配置一次导航抽屉,并在多个Activites上显示它? 问题答案: 为此,只需创建一个实现抽屉的BaseActivity类,然后让所有其他活动扩展该抽屉即可。