巧解Android時區加載過慢的問題 – Android移動開發技術文章_手機開發 Android移動開發教學課程

當在Android系統中切換語言時,會帶來一個有趣的bug:SimpleDateFormat在處理“z”時區字段時會花費很長的時間。如果你在一個ListView裡多次調用這個方法,就會發現這個ListView在滾動時很不流暢。控制臺相關輸出如下所示:


view plaincopy to clipboardprint?
I/Resources(  471): Loaded time zone names for en_US in 1904ms.  
I/Resources(  471): Loaded time zone names for en_US in 1400ms.  
I/Resources(  471): Loaded time zone names for en_US in 1260ms.  
I/Resources(  471): Loaded time zone names for en_US in 1360ms.  
I/Resources(  471): Loaded time zone names for en_US in 1232ms.  
I/Resources(  471): Loaded time zone names for en_US in 1344ms.  
I/Resources(  471): Loaded time zone names for en_US in 1228ms. 
I/Resources(  471): Loaded time zone names for en_US in 1904ms.
I/Resources(  471): Loaded time zone names for en_US in 1400ms.
I/Resources(  471): Loaded time zone names for en_US in 1260ms.
I/Resources(  471): Loaded time zone names for en_US in 1360ms.
I/Resources(  471): Loaded time zone names for en_US in 1232ms.
I/Resources(  471): Loaded time zone names for en_US in 1344ms.
I/Resources(  471): Loaded time zone names for en_US in 1228ms.


    這是因為時區字段在Android系統中是被設計為延遲初始化的,隻有在第一次使用到時才會去獲取,並保存在緩存中,隨後都會從這個緩存中去獲取。但是根據之前SimpleDateFormat API的設計,沒有方法來達到這個目的。在Android官方issues裡也反復提到瞭這個問題,從2009年被發現到現在,都始終沒有解決。


    在期待Android系統修復這個問題或者越來越快的系統硬件支持之外,基本很難處理這個系統原生的bug,但是我們可以通過一個簡單的辦法來改進這個問題。核心的思路就是緩存時區帶來的偏移值。我們隻需要在第一次加載時獲取這個偏移值並存儲,然後在以後每一次根據這個偏移值算出真實的時間值,代碼如下:


view plaincopy to clipboardprint?
public static long cachedTime = -1;  
public static long mtimeToLong(String time) {  
    SimpleDateFormat format = new SimpleDateFormat(  
            “yyyy-MM-dd HH:mm:ss.SSS”); // 獲取沒有時區的時間格式  
    try {  
        Date date = format.parse(time);  
          
        if(cachedTime == -1) { // 第一次取值時  
            SimpleDateFormat localFormat = new SimpleDateFormat(  
                “yyyy-MM-dd HH:mm:ss.SSSz”); // 獲取有時區的時間格式  
              
            Date localDate = localFormat.parse(time);  
              
            long localTime = localDate.getTime();  
            cachedTime = localTime – date.getTime(); // 計算出差值並存儲  
            return localTime;  
        } else { // 第一次之後的取值  
            return date.getTime() + cachedTime;  
        }  
    } catch (ParseException e) {  
        e.printStackTrace();  
        return 0;  
    }  

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *