當在Android系統中切換語言時,會帶來一個有趣的bug:SimpleDateFormat在處理“z”時區欄位時會花費很長的時間。如果你在一個ListView裡多次調用這個方法,就會發現這個ListView在滾動時很不流暢。控制台相關輸出如下所示:
I/Resources( 471): Loaded time zone names for en_US in 1904ms.<br />I/Resources( 471): Loaded time zone names for en_US in 1400ms.<br />I/Resources( 471): Loaded time zone names for en_US in 1260ms.<br />I/Resources( 471): Loaded time zone names for en_US in 1360ms.<br />I/Resources( 471): Loaded time zone names for en_US in 1232ms.<br />I/Resources( 471): Loaded time zone names for en_US in 1344ms.<br />I/Resources( 471): Loaded time zone names for en_US in 1228ms.
其他開發人員的反饋可見:
http://stackoverflow.com/questions/3905545/android-load-timezone-too-long-loaded-time-zone-names-for-en-us
http://stackoverflow.com/questions/2853058/weird-parsing-date-string-error-in-android-2-0-emulator
這是因為時區欄位在Android系統中是被設計為延遲初始化的,只有在第一次使用到時才會去擷取,並儲存在緩衝中,隨後都會從這個緩衝中去擷取。但是根據之前SimpleDateFormat API的設計,沒有方法來達到這個目的。在Android官方issues裡也反覆提到了這個問題,從2009年被發現到現在,都始終沒有解決。參見:http://code.google.com/p/android/issues/detail?id=3147和http://code.google.com/p/android/issues/detail?id=16126。
在期待Android系統修複這個問題或者越來越快的系統硬體支援之外,基本很難處理這個系統原生的bug,但是我們可以通過一個簡單的辦法來改進這個問題。核心的思路就是緩衝時區帶來的位移值。我們只需要在第一次載入時擷取這個位移值並儲存,然後在以後每一次根據這個位移值算出真實的時間值,代碼如下:
public static long cachedTime = -1;<br />public static long mtimeToLong(String time) {<br />SimpleDateFormat format = new SimpleDateFormat(<br />"yyyy-MM-dd HH:mm:ss.SSS"); // 擷取沒有時區的時間格式<br />try {<br />Date date = format.parse(time);</p><p>if(cachedTime == -1) { // 第一次取值時<br />SimpleDateFormat localFormat = new SimpleDateFormat(<br />"yyyy-MM-dd HH:mm:ss.SSSz"); // 擷取有時區的時間格式</p><p>Date localDate = localFormat.parse(time);</p><p>long localTime = localDate.getTime();<br />cachedTime = localTime - date.getTime(); // 計算出差值並儲存<br />return localTime;<br />} else { // 第一次之後的取值<br />return date.getTime() + cachedTime;<br />}<br />} catch (ParseException e) {<br />e.printStackTrace();<br />return 0;<br />}<br />}
通過這種簡單的方式我們可以暫時解決Android系統的疑難bug,帶來了一種解決問題的不同思路。