为什么resolveInfo.loadLabel()如此可笑地慢?

时间:2015-07-02 15:23:30

标签: java android performance android-launcher

在我的主屏幕更换应用程序中,我必须获取所有已安装应用程序的列表,以将它们放入应用程序抽屉中。因此,以下方法可以在每个应用程序上运行;

public static App fromResolveInfo (Context context, PackageManager pacMan, AppManager appManager, ResolveInfo resInf)
{
    String label = resInf.loadLabel (pacMan).toString ();
    String packageName = resInf.activityInfo.applicationInfo.packageName;
    String activityName = resInf.activityInfo.name;

    App app = new App (context, appManager);
    app.setLabel (label);
    app.setPackageName (packageName);
    app.setActivityName (activityName);

    AppIcon icon = null;
    if (appManager.isIconPackLoaded ())
        icon = appManager.getIconPack ().getIconForApp (app);
    if (icon == null)
        icon = appManager.getIconPack ().getFallbackIcon (resInf.loadIcon (pacMan));

    app.setIcon (icon);

    return app;
}

问题是这里存在瓶颈,而且他并没有像我原先预期的那样加载图标。方法的第一行(String label = resInf.loadLabel (pacMan).toString ();)可以占用0到250毫秒之间的任何值(在相对高端的设备上)。在旧设备上,这成为一个真正的问题 在我的测试中,我注意到当较慢的设备是多任务处理并且由于某种原因必须重新加载应用程序抽屉时,此操作可能需要 30秒才能完成(在所有安装的应用程序)。

缓存可以为此提供一个潜在的解决方案,但是如果应用程序的名称发生变化(偶尔会发生)会怎么样?我必须从缓存中获取标签,然后在单独的线程中循环遍历所有应用程序并更正它们已更改的标签。这可能会提供一个解决方案,但它似乎更像是一个肮脏的黑客,而不是一个真正的好解决方案。

有没有更快的方法来获取应用程序活动的标签?另外,为什么Android需要如此荒谬的时间来获取应用程序的标签,和/或有什么我可以做的吗?

2 个答案:

答案 0 :(得分:1)

您可以获得标签:

String label = (String) resInf.activityInfo.applicationInfo.loadLabel(pacMan);

如果您比较这两种方法的Android源代码,您会注意到applicationInfo中的一个代码要执行的代码较少。也许瓶颈在于额外的代码。我个人从未比较那些因为我从未发现过这样的问题的执行时间。

答案 1 :(得分:0)

回答原始问题“为什么?” ...正如其他人所指出的那样,问题在于标签已本地化,这意味着它是根据资源从资源(从应用APK文件)中读取的。但是对我来说,这本身并不能解释效果。

我一直在开发一个可以查看已安装应用程序的应用程序,并且在具有约150个应用程序的4核armeabi-v7a系统上,仅获取一个应用程序标签列表就需要大约10秒钟。很痛苦。

我假设它正在使用ClassLoader来从类文件之类的资源中读取资源-这确实可以非常快-在现代系统上几乎可以立即处理数百个类文件。好吧,我认为它不再使用ClassLoader。但是原则上...

一百个左右的文件处理时间应该少于10秒。就其本身而言,这不能解释我看到的滞后。

因此,我通过创建Resources对象,打开Assets来跟踪这些调用,最终检索了一个标签String。我看到的是synchronized代码的一层又一层。每个应用标签都需要重新调用所有这些内容。现在,可以使Java停止运行。

当然,只要获取一个标签就没关系。但是,当您要获取所有 时,它的总和就会增加。

我希望深入了解它,并找到可以在一个同步循环中调用的内容。但是在android-29源代码的底部,在另一个同步块中,我找到了对特定于SDK的nativeGetResourceValue()的调用。也就是说,无法以某种方式将其重新滚动以使其更加有效,并且还可以在其他SDK上运行。

另一方面,操作系统可以非常快速地显示按标签排序的应用程序列表。这意味着它将在某处维护一张应用程序标签表。我们可以访问吗?

如果有某种方法可以更快地获取应用标签列表,我很想听听。 (不,我不需要听到有关创建自己的缓存的信息-无论如何我都可以这样做。)