當一個 Android App 退到後臺以後,只要他沒有被殺死,那麼他作什麼事情你們都不要奇怪,由於這就是 Android。可是當用戶知道一個你一個 App 退到後臺以後還在持續作無效的動畫,而這個動畫徹底是無心義的,並且用戶還不知道他在作動畫,消耗用戶那可憐的電量的時候,輕則被多任務殺掉,禁止後臺運行,重則直接卸載。android
通常的開發者很難發現這個問題,可是若是你常用 Systrace ,多開幾十個應用而後退回到桌面,左右滑動抓取 Systrace ,就能夠很容易發現,總有那麼幾個後臺的應用,還在頻繁地作無效的動畫。bash
這裏說的後臺作動畫,指的是因爲某種緣由,應用在退到後臺以後,用戶看不到任何這個 App 界面的時候,他仍然在後臺不斷地更新,耗費 CPU。引發這個問題的緣由可能有好多個,畢竟 往 Choreographer 扔 CALLBACK_ANIMATION 的地方太多了,並且每一個應用可能都不同,但最終仍是須要各個應用去作修復,但願看到這篇文章的開發者,檢查一下本身的應用是否有這個問題。app
下面咱們就以一個實例,從技術的角度來看一下事件發生時候的狀況。ide
咱們在使用網易新聞後,將網易新聞退到後臺,而後左右滑動桌面,抓 Systrace 來看:oop
網易新聞到後臺以後還在持續作 Animation 的回調(紅框內)動畫
放大每個 doFrame 來看ui
咱們把這份 Trace 上的 cpu 部分全選,而後下面按照 Wall Duration 排序,能夠發現網易新聞後臺動畫執行時間最長this
抓對應的 MethodTrace 來看,就是在作動畫,沒有進行關閉 ,動畫依舊在每一幀進行 onAnimationUpdate 的回調 ,spa
啓動 QQ 音樂,而後回到桌面, 左右滑動桌面並抓取 Systrace 和 MethodTracecode
抓取了 QQ 音樂的後臺動畫時候的 MethodTrace 發現,也是因爲退到後臺以後,沒有暫停動畫致使的, 並且 QQ 音樂有三個動畫沒有中止,比網易新聞還要嚴重一些
放大後能夠看到
固然也不是每個都是 airbnb 的 lottie 動畫庫引發的,好比下面這個,就是普通的動畫沒有結束
根本緣由是應用在不可見以後,沒有將動畫暫停,致使應用切換到後臺以後,依然在刷新動畫的回調,但此時因爲是不可見的,不會觸發 Input Callback 和 draw Callback ,因此也不會有任何的繪製操做,也就是說這個 Animation 的刷新徹底是沒有意義的(固然也有多是業務需求?)
上面兩個例子裏面,網易新聞和 QQ 音樂都是由於使用了 Lottie 來實現動畫,可是沒有正確的關閉致使的。
Lottie 庫的 issue 列表裏面有人提到了這個狀況:
提出問題:
I recently did some benchmarking on an app which uses lottie to do some animations (autoplay and looping). I noticed that there is quite some CPU usage when the app is in the background and tried to investigate.
It seems to me looping animations do not pause/stop when the containing LottieAnimationView is off screen, and/or the Activity is paused.
I believe this is due to the cleanup code being only in onDetachedFromWindow() which is not necessarily being called once the Activity goes into a paused state and most definitely not, when the view is simply not visible (GONE, INVISIBLE ) anymore.
解決方法:
Overriding LottieAnimationView and doing the following solves the visibility issue for me and Lottie is paused when not visible.
@Override
protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
if (visibility == VISIBLE && wasAnimatingWhenVisibilityChanged) {
resumeAnimation();
} else {
if (isAnimating()) {
wasAnimatingWhenVisibilityChanged = true;
pauseAnimation();
} else {
wasAnimatingWhenVisibilityChanged = false;
}
}
}
複製代碼
總之就是 : 當 App 不可見的時候,中止全部的動畫。
小廠系統研發工程師 , 更多信息能夠點擊 關於我 , 很是但願和你們一塊兒交流 , 共同進步 .
一我的能夠走的更快 , 一羣人能夠走的更遠