此問題在oppo R9 系列的手機(jī)出現(xiàn)較多,而且主要集中在Android 5.1-6.0的手機(jī)系統(tǒng)。
TimeoutException,在Android 系統(tǒng)里會出現(xiàn)下面這些吴旋,在釋放資源時,因耗時導(dǎo)致的寒亥,可能不是10s,可能會是20s,30s邮府,60s,120s荧关。具體跟手機(jī)有關(guān)溉奕。
android.database.CursorWindow.finalize() timed out after 10 seconds
java.util.regex.Matcher.finalize() timed out after 10 seconds
android.graphics.Bitmap$BitmapFinalizer.finalize() timed out after 10 seconds
org.apache.http.impl.conn.SingleClientConnManager.finalize() timed out after 10 seconds
java.util.concurrent.ThreadPoolExecutor.finalize() timed out after 10 seconds
android.os.BinderProxy.finalize() timed out after 10 seconds
android.graphics.Path.finalize() timed out after 10 seconds
這些都 會導(dǎo)致此閃退出現(xiàn)。這個bug,在stackoverflow數(shù)量還是比較 多的忍啤。
經(jīng)過google查詢加勤,最終在
具體的分析及解決可以詳細(xì)閱讀滴滴移動團(tuán)隊(duì) 分享的文章
https://mp.weixin.qq.com/s/uFcFYO2GtWWiblotem2bGg
我按滴滴的文章,還是會閃退同波,對于 app的異常監(jiān)聽鳄梅,可參考之前的一篇文章 http://www.reibang.com/p/2cb297395bd4 。
由于我們App還集成了一些第三方 的SDK,這個SDK 里都有實(shí)現(xiàn)對 異常 的攔截處理未檩,如jpush戴尸、umeng、神策打點(diǎn)冤狡。所以當(dāng)我在自己的
Thread.UncaughtExceptionHandler孙蒙,處理完后项棠,會再拋出一個java.lang.RuntimeException,最終還是會走異常的處理邏輯挎峦,造成App閃退香追。
1 xxxxx.CrashHandler.uncaughtException()
2 com.umeng.analytics.pro.j.uncaughtException()
3 com.qiyukf.unicorn.j.d$1.uncaughtException()
4 cn.jiguang.a.a.c.e.uncaughtException()
5 com.tencent.bugly.crashreport.crash.e.b()
6 com.tencent.bugly.crashreport.crash.e.uncaughtException()
7 java.lang.Daemons$FinalizerWatchdogDaemon.finalizerTimedOut(Daemons.java:316)
8 java.lang.Daemons$FinalizerWatchdogDaemon.run(Daemons.java:238)
9 java.lang.Thread.run(Thread.java:833)
2019-07-23 11:24:31.277 11406-11419/xxxx E/[ FinalizerWatchdogDaemon:CrashHandler:uncaughtException():62 ]: ==thread==FinalizerWatchdogDaemon
2019-07-23 11:24:31.278 11406-11419/xxxx E/[ FinalizerWatchdogDaemon:CrashHandler:uncaughtException():67 ]: ===ex=java.util.concurrent.TimeoutException: xxxx.ui.index.FinlaizeTimeoutObject.finalize() timed out after 60 seconds
2019-07-23 11:24:31.278 11406-11419/xxxx E/[ FinalizerWatchdogDaemon:CrashHandler:uncaughtException():70 ]: ===ignore=
2019-07-23 11:24:31.280 11406-11419/xxxx E/AndroidRuntime: FATAL EXCEPTION: FinalizerWatchdogDaemon
Process: xxxx, PID: 11406
java.lang.RuntimeException: java.util.concurrent.TimeoutException: xxxx.ui.index.FinlaizeTimeoutObject.finalize() timed out after 60 seconds
at cn.jiguang.a.a.c.e.uncaughtException(Unknown Source:69)
at com.xiaomi.mipush.sdk.z.uncaughtException(Unknown Source:25)
at com.loc.ai.uncaughtException(Unknown Source:21)
at com.loc.ay.uncaughtException(Unknown Source:232)
at java.lang.Daemons$FinalizerWatchdogDaemon.finalizerTimedOut(Daemons.java:424)
at java.lang.Daemons$FinalizerWatchdogDaemon.runInternal(Daemons.java:285)
at java.lang.Daemons$Daemon.run(Daemons.java:105)
at java.lang.Thread.run(Thread.java:764)
Caused by: java.util.concurrent.TimeoutException: xxxx.ui.index.FinlaizeTimeoutObject.finalize() timed out after 60 seconds
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:373)
at java.lang.Thread.sleep(Thread.java:314)
at xxxx.ui.index.FinlaizeTimeoutObject.finalize(FinlaizeTimeoutObject.java:11)
at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:252)
at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:239)
at java.lang.Daemons$Daemon.run(Daemons.java:105)
at java.lang.Thread.run(Thread.java:764)
2019-07-23 11:24:34.356 11406-11419/xxxx E/[ FinalizerWatchdogDaemon:CrashHandler:uncaughtException():62 ]: ==thread==FinalizerWatchdogDaemon
2019-07-23 11:24:34.356 11406-11419/xxxx E/[ FinalizerWatchdogDaemon:CrashHandler:uncaughtException():67 ]: ===ex=java.lang.RuntimeException: java.util.concurrent.TimeoutException: xxxx.ui.index.FinlaizeTimeoutObject.finalize() timed out after 60 seconds
2019-07-23 11:24:34.356 11406-11419/xxxx E/[ FinalizerWatchdogDaemon:CrashHandler:uncaughtException():72 ]: ===ex=java.lang.RuntimeException: java.util.concurrent.TimeoutException: xxxx.ui.index.FinlaizeTimeoutObject.finalize() timed out after 60 seconds
2019-07-23 11:24:34.358 11406-11419/xxxx E/CrashReport: CrashReport has not been initialed! pls to call method 'initCrashReport' first!
2019-07-23 11:24:37.359 11406-11419/xxxx E/Tinker.TinkerUncaughtExceptionHandler: uncaughtException:java.util.concurrent.TimeoutException: xxxx.ui.index.FinlaizeTimeoutObject.finalize() timed out after 60 seconds
2019-07-23 11:24:37.359 11406-11419/xxxx W/Tinker.TinkerUncaughtExceptionHandler: tinker is not loaded
2019-07-23 11:24:37.361 11406-11419/xxxx E/Tinker.UncaughtHandler: TinkerUncaughtHandler catch exception:java.lang.RuntimeException: java.util.concurrent.TimeoutException: xxxx.ui.index.FinlaizeTimeoutObject.finalize() timed out after 60 seconds
at cn.jiguang.a.a.c.e.uncaughtException(Unknown Source:69)
at com.xiaomi.mipush.sdk.z.uncaughtException(Unknown Source:25)
at com.loc.ai.uncaughtException(Unknown Source:21)
at com.loc.ay.uncaughtException(Unknown Source:232)
at java.lang.Daemons$FinalizerWatchdogDaemon.finalizerTimedOut(Daemons.java:424)
at java.lang.Daemons$FinalizerWatchdogDaemon.runInternal(Daemons.java:285)
at java.lang.Daemons$Daemon.run(Daemons.java:105)
at java.lang.Thread.run(Thread.java:764)
Caused by: java.util.concurrent.TimeoutException: xxxx.ui.index.FinlaizeTimeoutObject.finalize() timed out after 60 seconds
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:373)
at java.lang.Thread.sleep(Thread.java:314)
at xxxx.ui.index.FinlaizeTimeoutObject.finalize(FinlaizeTimeoutObject.java:11)
at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:252)
at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:239)
at java.lang.Daemons$Daemon.run(Daemons.java:105)
at java.lang.Thread.run(Thread.java:764)
如何設(shè)計(jì)出一個TimeoutException。
先自己隨便寫一下類坦胶,暫且叫透典,CustomTimeoutException吧。重寫finalize()方法顿苇,在里面將線程sleep 100s峭咒,這個是測試出來的,上文有提到纪岁,不同的手機(jī) 讹语、系統(tǒng)對應(yīng)超時時間不一樣,我用了一個魅族 5.1的手機(jī) 蜂科,20s,在小米 note 2 8.0 系統(tǒng) 是60s.
public class CustomTimeoutException {
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("====開始Timeout處理====");
// 每個手機(jī)觸發(fā) Timeout 的時長不同顽决,看情況修改
Thread.sleep(100*1000);
System.out.println("====結(jié)束Timeout處理====");
}
}
然后在一個頁面加一個點(diǎn)擊事件,throwsTimeout()
private void throwsTimeout(){
new Thread(()->{
new CustomTimeoutException();
Runtime.getRuntime().gc();
System.runFinalization();
}).start();
}
點(diǎn)擊按鈕后导匣,我們會看到打印 :
但遲遲不見: 日志.
注意才菠,我在測試時,并不是每次出現(xiàn)贡定,有時會打印“====結(jié)束Timeout處理====” 日志赋访,猜測可能跟我 開啟一下線程處理這個有關(guān),因?yàn)槲也]有阻塞 UI線程缓待,App還是可以 繼續(xù)使用蚓耽。
為什么要開啟一個線程,不然很容易造成ANR(10s),無法復(fù)現(xiàn)此問題旋炒。
經(jīng)過這個步悠,我最終并沒有完全按滴滴提供的方法處理此異常。只要檢測到是線程名是 FinalizerWatchdogDaemon,我就忽略此異常瘫镇,這樣鼎兽,這樣也就不會被其它的 異常處理 類強(qiáng)制 退出App。
/**
* 當(dāng)UncaughtException發(fā)生時會轉(zhuǎn)入該函數(shù)來處理
*/
@Override
public void uncaughtException(Thread thread, Throwable ex) {
System.out.println("==thread=="+thread.getName());
System.out.println("===ex="+ex);
System.out.println("===isTimeOut="+(ex instanceof TimeoutException));
System.out.println("=isThread=="+
TextUtils.equals(thread.getName(),
"FinalizerWatchdogDaemon"));
if(TextUtils.equals(thread.getName(),
"FinalizerWatchdogDaemon")) {
//&&ex instanceof TimeoutException)
System.out.println("===ignore=");
}else {
// 正常處理異常铣除,該上拋的上拋谚咬,該交給系統(tǒng) 處理的交給系統(tǒng)處理。
}
雖然問題是解決了尚粘,但這并沒有從根本上解決這個問題择卦,真的要減少此異常的話,還是得規(guī)范開發(fā)的,盡量讓App減少 GC的回收秉继。