Android中各種Time API詳細
1、時間API
為瞭跟蹤性能,我們需要測量時間間隔,即兩個時間點之間的差異。 JDK
為我們提供瞭兩種獲取當前時間的方法:
// Milliseconds since Unix epoch (00:00:00 UTC on 1 January 1970) System.currentTimeMillis() // Nanoseconds since the VM started. System.nanoTime()
Android
提供瞭一個 SystemClock
類,它增加瞭一些:
// (API 29) Clock that starts at Unix epoch. // Synchronized using the device's location provider. SystemClock.currentGnssTimeClock() // Milliseconds running in the current thread. SystemClock.currentThreadTimeMillis() // Milliseconds since boot, including time spent in sleep. SystemClock.elapsedRealtime() // Nanoseconds since boot, including time spent in sleep. SystemClock.elapsedRealtimeNanos() // Milliseconds since boot, not counting time spent in deep sleep. SystemClock.uptimeMillis()
我們應該選擇哪一個? SystemClock
的 javadoc
有助於回答這個問題:
System#currentTimeMillis
可以由用戶或電話網絡設置,因此時間可能會不可預測地向後或向前跳躍。 間隔或經過時間測量應使用不同的時鐘。
SystemClock#uptimeMillis
在系統進入深度睡眠時停止。 這是大多數間隔計時的基礎,例如 Thread#sleep(long)
、Object#wait(long)
和 System#nanoTime
。 當間隔不跨越設備休眠時,該時鐘適用於間隔計時。
SystemClock#elapsedRealtime
和 SystemClock#elapsedRealtimeNanos
包括深度睡眠。 該時鐘是通用間隔計時的推薦基礎。
應用程序的性能對深度睡眠中發生的事情沒有影響,所以我們最好的選擇是 SystemClock.uptimeMillis()
和 System.nanoTime()
2、uptimeMillis() vs nanoTime()
System.nanoTime()
比 uptimeMillis()
更精確,但這僅對微基準測試有用。 在生產中跟蹤性能時,我們需要毫秒級的分辨率。
讓我們比較一下它們的性能影響。 我克隆瞭 Android Benchmark Samples
存儲庫並添加瞭以下測試:
@LargeTest @RunWith(AndroidJUnit4::class) class TimingBenchmark { @get:Rule val benchmarkRule = BenchmarkRule() @Test fun nanoTime() { benchmarkRule.measureRepeated { System.nanoTime() } } @Test fun uptimeMillis() { benchmarkRule.measureRepeated { SystemClock.uptimeMillis() } } }
在運行 Android 10 的 Pixel 3 上的結果:
System.nanoTime()
中值時間:208 ns
SystemClock.uptimeMillis()
中值時間:116 ns
SystemClock.uptimeMillis()
幾乎快兩倍! 雖然這種差異應該不會對應用程序產生任何有意義的影響,但我們能弄清楚為什麼它要快得多嗎?
3、uptimeMillis() 實現
SystemClock.uptimeMillis()
實現為帶有@CriticalNative
註釋的本機方法。 CriticalNative
為不包含對象的方法提供更快的 JNI 轉換。
public final class SystemClock { @CriticalNative native public static long uptimeMillis(); }
原生實現在 SystemClock.c++
中:
int64_t uptimeMillis() { int64_t when = systemTime(SYSTEM_TIME_MONOTONIC); return (int64_t) nanoseconds_to_milliseconds(when); }
systemTime() 在 Timers.cpp 中定義:
nsecs_t systemTime(int clock) { static constexpr clockid_t clocks[] = { CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID, CLOCK_BOOTTIME }; timespec t = {}; clock_gettime(clocks[clock], &t); return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec; }
4、nanoTime() 實現
System.nanoTime()
也被實現為帶有@CriticalNative
註釋的本地方法。
public final class System { @CriticalNative public static native long nanoTime(); }
本地實現在 System.c 中:
static jlong System_nanoTime() { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); return now.tv_sec * 1000000000LL + now.tv_nsec; }
這兩個實現其實很相似,都調用clock_gettime()
。
事實證明,@CriticalNative
最近才被添加到 System.nanoTime()
,這就解釋瞭為什麼它變慢瞭!
結論:
在生產應用中跟蹤性能時:
對於大多數用例,毫秒分辨率就足夠瞭。 要測量時間間隔,請使用 SystemClock.uptimeMillis()
或 System.nanoTime()
。 後者在較舊的 Android
版本上速度較慢,但這在這裡無關緊要。
到此這篇關於Android
中各種Time API
詳細的文章就介紹到這瞭,更多相關Android中各種Time API內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Spring Boot源碼實現StopWatch優雅統計耗時
- Java Thread之Sleep()案例詳解
- Android消息機制Handler深入理解
- C++使用chrono庫處理日期和時間的實現方法
- Springboot之如何統計代碼執行耗時時間