Android Java - Joda Date很慢

Mar*_*nop 56 android jodatime

在Android上使用Joda 1.6.2

以下代码挂起约15秒.

DateTime dt = new DateTime();
Run Code Online (Sandbox Code Playgroud)

最初发布这篇文章 Android Java - Joda Date在Eclipse/Emulator中很慢 -

刚试了一次它仍然没有更好.有没有其他人有这个问题或知道如何解决它?

plo*_*man 63

我也遇到了这个问题.Jon Skeet的怀疑是正确的,问题是时区的加载效率非常低,打开一个jar文件,然后读取清单试图获取这些信息.

但是,简单地调用DateTimeZone.setProvider([custom provider instance ...])是不够的,因为由于对我没有意义的原因,DateTimeZone有一个静态初始化器,它调用它getDefaultProvider().

为了完全安全,您可以通过在调用joda中的任何内容之前设置此系统属性来覆盖此默认值.

例如,在您的活动中添加以下内容:

@Override
public void onCreate(Bundle savedInstanceState) {
    System.setProperty("org.joda.time.DateTimeZone.Provider", 
    "com.your.package.FastDateTimeZoneProvider");
}
Run Code Online (Sandbox Code Playgroud)

然后你所要做的就是定义FastDateTimeZoneProvider.我写了以下内容:

package com.your.package;

public class FastDateTimeZoneProvider implements Provider {
    public static final Set<String> AVAILABLE_IDS = new HashSet<String>();

    static {
        AVAILABLE_IDS.addAll(Arrays.asList(TimeZone.getAvailableIDs()));
    }

    public DateTimeZone getZone(String id) {
        if (id == null) {
            return DateTimeZone.UTC;
        }

        TimeZone tz = TimeZone.getTimeZone(id);
        if (tz == null) {
            return DateTimeZone.UTC;
        }

        int rawOffset = tz.getRawOffset();

            //sub-optimal. could be improved to only create a new Date every few minutes
        if (tz.inDaylightTime(new Date())) {
            rawOffset += tz.getDSTSavings();
        }

        return DateTimeZone.forOffsetMillis(rawOffset);
    }

    public Set getAvailableIDs() {
        return AVAILABLE_IDS;
    }
}
Run Code Online (Sandbox Code Playgroud)

我已经测试了这个,它似乎适用于Android SDK 2.1+和joda版本1.6.2.它当然可以进一步优化,但在分析我的应用程序(mogwee)时,这会将 DateTimeZone初始化时间从~500ms减少到~18ms.

如果您使用proguard构建应用程序,则必须将此行添加到proguard.cfg,因为Joda希望类名完全按照您的指定:

-keep class com.your.package.FastDateTimeZoneProvider
Run Code Online (Sandbox Code Playgroud)


Jon*_*eet 23

我强烈怀疑这是因为它必须为默认时区建立ISO年表,这可能涉及读取所有时区信息.

你可以ISOChronology.getInstance()先通过调用,然后再调用一次来验证这一点new DateTime().我怀疑它会很快.

您知道哪些时区与您的申请相关吗?您可能会发现,通过使用非常简化的时区数据库重建Joda Time,您可以更快地完成整个过程.或者,DateTimeZone.setProvider()使用您自己的实现进行调用Provider,但不会执行任何工作.

这是值得检查是否这实际上是在第一个问题,当然:)你可能想尝试明确地传递在UTC时区,这将不需要读取时区数据库...但你永远不知道你什么时候会无意中触发调用,它确实需要的默认时区,此时你会招致同样的成本.


Tyl*_*ier 10

我的应用程序中只需要UTC.所以,按照unchek的建议,我用了

System.setProperty("org.joda.time.DateTimeZone.Provider", "org.joda.time.tz.UTCProvider");
Run Code Online (Sandbox Code Playgroud)

org.joda.time.tz.UTCProvider实际上JodaTime使用它作为辅助备份,所以我想为什么不将它用作主要用途?到现在为止还挺好.它加载速度很快.


Ric*_*rdo 8

如果您必须为您的日期进行精确的时区计算,那么由plowman提供的最佳答案是不可靠的.以下是可能发生的问题示例:

假设您的DateTime对象设置为当天凌晨4点,即夏令时开始后一小时.当Joda FastDateTimeZoneProvider在凌晨3:00之前(即夏令时之前)检查提供者时,它将获得DateTimeZone具有错误偏移的对象,因为该tz.inDaylightTime(new Date())检查将返回false.

我的解决方案是采用最近发布的joda-time-android库.它使用Joda的核心,但确保仅根据需要从原始文件夹加载时区.使用gradle轻松设置.在您的项目中,扩展Application该类并在其上添加以下内容onCreate():

public class MyApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        JodaTimeAndroid.init(this);
    }
}
Run Code Online (Sandbox Code Playgroud)

作者去年写了一篇关于它的博客文章.