崩潰bug日誌總結1
阿新 • • 發佈:2018-12-16
目錄介紹
- 1.1 java.lang.UnsatisfiedLinkError找不到so庫異常
- 1.2 java.lang.IllegalStateException非法狀態異常
- 1.3 android.content.res.Resources$NotFoundException
- 1.4 java.lang.IllegalArgumentException引數不匹配異常
- 1.5 IllegalStateException:Can’t compress a recycled bitmap
- 1.6 java.lang.NullPointerException空指標異常
- 1.7 android.view.WindowManager$BadTokenException異常
- 1.8 java.lang.ClassCastException類轉化異常
- 1.9 1.9 Toast執行在子執行緒問題,handler問題
好訊息
- 部落格筆記大彙總【16年3月到至今】,包括Java基礎及深入知識點,Android技術部落格,Python學習筆記等等,還包括平時開發中遇到的bug彙總,當然也在工作之餘收集了大量的面試題,長期更新維護並且修正,持續完善……開源的檔案是markdown格式的!同時也開源了生活部落格,從12年起,積累共計47篇[近20萬字],轉載請註明出處,謝謝!
- 如果覺得好,可以star一下,謝謝!當然也歡迎提出建議,萬事起於忽微,量變引起質變!
1.1 java.lang.UnsatisfiedLinkError
- A.詳細崩潰日誌資訊
# main(1) java.lang.UnsatisfiedLinkError dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.paidian.hwmc-1/base.apk", dex file "/data/app/com.paidian.hwmc-1/base.apk"],nativeLibraryDirectories=[/data/app/com.paidian.hwmc-1/lib/arm64, /data/app/com.paidian.hwmc-1/base.apk!/lib/arm64-v8a, /vendor/lib64, /system/lib64]]] couldn't find "libijkffmpeg.so"
- B.檢視崩潰類資訊
- 這個異常類的大意是:如果Java虛擬機器找不到宣告為
本機
的方法的適當本機語言定義,則引發。
public class UnsatisfiedLinkError extends LinkageError { private static final long serialVersionUID = -4019343241616879428L; public UnsatisfiedLinkError() { super(); } public UnsatisfiedLinkError(String s) { super(s); } }
- 這個異常類的大意是:如果Java虛擬機器找不到宣告為
- C.專案中異常分析
- 根據實際專案可知,當準備播放視訊時,找不到libijkffmpeg.so這個庫,導致直接崩潰。
- D.引發崩潰日誌的流程分析
- F.解決辦法
- 報這個錯誤通常是so庫載入失敗,或者找不到準備執行的JNI方法:
- 1.建議檢查so在安裝的過程中是否丟失,沒有放入指定的目錄下;
- 2.呼叫loadLibrary時檢查是否呼叫了正確的so檔名,並對其進行捕獲,進行相應的處理,防止程式發生崩潰;
- 3.檢查下so的架構是否跟裝置架構一至(如在64-bit架構下呼叫32-bit的so)。
- 程式碼展示
ndk { //根據需要 自行選擇新增的對應cpu型別的.so庫。 //abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86', 'mips' abiFilters 'armeabi-v7a' } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) //這兩個是必須要加的,其它的可供選擇 compile 'tv.danmaku.ijk.media:ijkplayer-java:0.8.4' compile 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.4' //其他庫檔案 //compile 'tv.danmaku.ijk.media:ijkplayer-armv5:0.8.8' //compile 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8' //compile 'tv.danmaku.ijk.media:ijkplayer-x86:0.8.8' //compile 'tv.danmaku.ijk.media:ijkplayer-x86_64:0.8.8' }
- 報這個錯誤通常是so庫載入失敗,或者找不到準備執行的JNI方法:
1.2 java.lang.IllegalStateException非法狀態異常
- A.詳細崩潰日誌資訊
- onSaveInstanceState方法是在該Activity即將被銷燬前呼叫,來儲存Activity資料的,如果在儲存玩狀態後 再給它新增Fragment就會出錯。
IllegalStateException: Can not perform this action after onSaveInstanceState:
- B.檢視崩潰類資訊
- 在非法或不適當的時間呼叫方法的訊號。換句話說,Java環境或Java應用程式沒有處於請求操作的適當狀態。
public class IllegalStateException extends RuntimeException { public IllegalStateException() { super(); } public IllegalStateException(String s) { super(s); } public IllegalStateException(String message, Throwable cause) { super(message, cause); } public IllegalStateException(Throwable cause) { super(cause); } static final long serialVersionUID = -1848914673093119416L; }
- C.專案中異常分析
- 分析
- D.引發崩潰日誌的流程分析
- F.解決辦法
- 解決辦法就是把commit()方法替換成 commitAllowingStateLoss()
- G.其他延申
- 錯誤型別大致為以下幾種:
java.lang.IllegalStateException:Can't change tag of fragment d{e183845 #0 d{e183845}}: was d{e183845} now d{e183845 #0 d{e183845}} java.lang.IllegalStateException:Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 37 path $.data
- 第一種:我在顯示fragment的程式碼中使用了:fragment.show(getSupportFragmentManager, fragment.toString());而這裡是因為兩次toString()結果不同,導致不同的tag指向的是同一個fragment。獲取fragment的tag的正確方法應該是使用其提供的fragment.getTag()方法。
- 第二種:該異常是由於伺服器錯誤返回的JSON字串和伺服器正常下時返回的JSON字串結構不同,導致利用Gson解析的時候報了一個異常:本該去解析集合卻強制去解析物件所致.解決辦法:在使用Gson解析JSON時try cash一下,不報錯按照正常邏輯繼續解析,報異常則處理為請求失敗邏輯即可.
1.3 android.content.res.Resources$NotFoundException
- A.詳細崩潰日誌資訊
- Android資源不是可繪製的(顏色或路徑)
Resource is not a Drawable (color or path): TypedValue{t=0x2/d=0x7f040151 a=2} android.view.LayoutInflater.createView(LayoutInflater.java:620)
- B.檢視崩潰類資訊
- 當找不到請求的資源時,資源API將引發此異常。
public static class NotFoundException extends RuntimeException { public NotFoundException() { } public NotFoundException(String name) { super(name); } public NotFoundException(String name, Exception cause) { super(name, cause); } }
- C.專案中異常分析
- 由於將圖片資源拷貝到了drawable-land-xhdpi目錄下,本來應該拷貝到drawable-xhdpi目錄下。
- D.引發崩潰日誌的流程分析
- F.解決辦法
- 1.引用的資源ID 是否能匹配到R.java檔案中定義的資源;
- 2.是否因為快取等原因導致編譯APK時未把資原始檔打包進去,可以把APK反編譯檢查下;
- 3.是否使用了一個錯誤的型別來引用了某個資源或者配置資源時存在錯誤;
- 4.是否將Int等整型變數作為了引數傳給了View.setText呼叫,這種情況下該整型變數將被認為是一個資源ID號去資源列表中查詢對應的資源,導致找不到對應資源錯誤;解決方法是做型別轉換View.setText(String.valueOf(Int id))。
1.4 java.lang.IllegalArgumentException引數不匹配異常
- A.詳細崩潰日誌資訊
- B.檢視崩潰類資訊
- 引數不匹配異常,通常由於傳遞了不正確的引數導致。
public class IllegalArgumentException extends RuntimeException { public IllegalArgumentException() { super(); } public IllegalArgumentException(String s) { super(s); } public IllegalArgumentException(String message, Throwable cause) { super(message, cause); } public IllegalArgumentException(Throwable cause) { super(cause); } private static final long serialVersionUID = -5365630128856068164L; }
- C.專案中異常分析
- D.引發崩潰日誌的流程分析
- F.解決辦法
- G.常見的出現場景
-
- Activity、Service狀態異常;
-
- 非法URL;
-
- UI執行緒操作。
- 4.Fragment中嵌套了子Fragment,Fragment被銷燬,而內部Fragment未被銷燬,所以導致再次載入時重複,在onDestroyView() 中將內部Fragment銷燬即可
- 5.在請求網路的回撥中使用了glide.into(view),view已經被銷燬會導致該錯誤
-
1.5 IllegalStateException:Can’t compress a recycled bitmap
- A.詳細崩潰日誌資訊
- 無法壓縮回收點陣圖
Can't compress a recycled bitmap com.paidian.hwmc.utils.i.a(FileUtils.java:75)
- B.檢視崩潰類資訊
- 如果點陣圖已被回收,則希望丟擲異常的方法將呼叫此值。知道了崩潰的具體位置,就該分析具體的原因呢!
public boolean compress(CompressFormat format, int quality, OutputStream stream) { checkRecycled("Can't compress a recycled bitmap"); //省略程式碼 return result; } //如果點陣圖已被回收,則希望丟擲異常的方法將呼叫此值。 private void checkRecycled(String errorMessage) { if (mRecycled) { throw new IllegalStateException(errorMessage); } }
- C.專案中異常分析
- 使用了已經被釋放過記憶體的物件。對於Bitmap:Bitmap bitmap=一個bitmap物件。使用過程中呼叫bitmap.recycle(),之後再使用bitmap就會報錯。
- D.引發崩潰日誌的流程分析
- bitmap.recycle()解釋如下所示,釋放與此點陣圖關聯的本機物件,並清除對畫素資料的引用。這將不會同步釋放畫素資料;它只允許在沒有其他引用的情況下對其進行垃圾收集。點陣圖被標記為“死”,這意味著如果呼叫getPixels()或setPixels(),它將丟擲異常,而不會繪製任何內容。此操作不能反轉,因此只有在確定沒有進一步使用點陣圖的情況下才應呼叫該操作。這是一個高階呼叫,通常不需要呼叫,因為當沒有對此點陣圖的引用時,普通GC程序將釋放此記憶體。
Free the native object associated with this bitmap, and clear the reference to the pixel data
- F.解決辦法
- 第一種:在使用bitmap前增加判斷,if (mBitmap.isRecycled()) return null;
- 第二種:
1.6 java.lang.NullPointerException空指標異常
- A.詳細崩潰日誌資訊
Please call the AutoSizeConfig#init() first com.paidian.hwmc.base.BaseApplication.initAutoSizeConfig(BaseApplication.java:386)
- B.檢視崩潰類資訊
- 空指標異常,也是十分常見的一個異常
public class NullPointerException extends RuntimeException { private static final long serialVersionUID = 5162710183389028792L; public NullPointerException() { super(); } public NullPointerException(String s) { super(s); } }
- C.專案中異常分析
- 空指標發生場景較多,是指某一個物件報null,這個使用去使用它的話就i會報該異常。
- D.引發崩潰日誌的流程分析
- F.解決辦法
- 空指標最為常見,也最容易規避,使用的時候一定要進行null check,採取不信任原則:
- 1.方法形參要判空後才使用;
- 2.全域性變數容易被系統回收或者更改,使用全域性變數前建議判空;
- 3.第三方介面的呼叫,對返回值進行判空。
- 4.請注意執行緒安全
- 空指標最為常見,也最容易規避,使用的時候一定要進行null check,採取不信任原則:
1.7 android.view.WindowManager$BadTokenException異常,Toast報錯Unable to add window
- A.詳細崩潰日誌資訊
android.view.WindowManager$BadTokenException Unable to add window -- token [email protected] is not valid; is your activity running?
- B.檢視崩潰類資訊
- 查詢報錯日誌是從哪裡來的
- C.專案中異常分析
- D.引發崩潰日誌的流程分析
- 這個異常發生在Toast顯示的時候,原因是因為token失效。通常情況下,一般是不會出現這種異常。但是由於在某些情況下, Android程序某個UI執行緒的某個訊息阻塞。導致 TN 的 show 方法 post 出來 0 (顯示) 訊息位於該訊息之後,遲遲沒有執行。這時候,NotificationManager 的超時檢測結束,刪除了 WMS 服務中的 token 記錄。刪除 token 發生在 Android 程序 show 方法之前。這就導致了上面的異常。
- 測試程式碼。模擬一下異常的發生場景,其實很容易,只需要這樣做就可以出現上面這個問題
Toast.makeText(this,"瀟湘劍雨-yc",Toast.LENGTH_SHORT).show(); try { Thread.sleep(20000); } catch (InterruptedException e) { e.printStackTrace(); }
- F.解決辦法
- 目前見過好幾種,思考一下那種比較好……
- 第一種,既然是報is your activity running,那可以不可以在吐司之前先判斷一下activity是否running呢?
- 第二種,丟擲異常增加try-catch,程式碼如下所示,最後仍然無法解決問題
- 按照原始碼分析,異常是發生在下一個UI執行緒訊息中,因此在上一個ui執行緒訊息中加入try-catch是沒有意義的。而且用到吐司地方這麼多,這樣做也不方便啦!
- 第三種,那就是自定義類似吐司Toast的view控制元件。個人建議除非要求非常高,不然不要這樣做。畢竟發生這種異常還是比較少見的
- G.哪些情況會發生該問題?
- UI 執行緒執行了一條非常耗時的操作,比如載入圖片等等,就類似上面用 sleep 模擬情況
- 程序退後臺或者息屏了,系統為了減少電量或者某種原因,分配給程序的cpu時間減少,導致程序內的指令並不能被及時執行,這樣一樣會導致程序看起來”卡頓”的現象
- 當TN丟擲訊息的時候,前面有大量的 UI 執行緒訊息等待執行,而每個 UI 執行緒訊息雖然並不卡頓,但是總和如果超過了 NotificationManager 的超時時間,還是會出現問題
1.8 java.lang.ClassCastException類轉化異常
- A.詳細崩潰日誌資訊
android.widget.FrameLayout cannot be cast to android.widget.RelativeLayout com.paidian.hwmc.goods.activity.GoodsDetailsActivity.initView(GoodsDetailsActivity.java:712)
- B.檢視崩潰類資訊
- 丟擲以指示程式碼試圖將物件強制轉換為它不是例項的子類。
public class ClassCastException extends RuntimeException { private static final long serialVersionUID = -9223365651070458532L; public ClassCastException() { super(); } public ClassCastException(String s) { super(s); } }
- C.專案中異常分析
- 該異常表示型別轉換異常,通常是因為一個類物件轉換為其他不相容類物件丟擲的異常,檢查你要轉換的類物件型別。
- D.引發崩潰日誌的流程分析
- F.解決辦法
- 一般在強制型別轉換時出現,例如如果A向B轉換,而A不是B的父類時,將產生java.lang.ClassCastException異常。一般建議做這時要使用instanceof做一下型別判斷,再做轉換。
- 該案例中,需要把FrameLayout更改成RelativeLayout就可以呢
1.9 Toast執行在子執行緒問題,handler問題
- A.詳細崩潰日誌資訊
- 先來看看問題程式碼,會出現什麼問題呢?
new Thread(new Runnable() { @Override public void run() { ToastUtils.showRoundRectToast("瀟湘劍雨-楊充"); } }).start();
- 報錯日誌如下所示:
- 然後找找報錯日誌從哪裡來的
- 子執行緒中吐司的正確做法,程式碼如下所示
new Thread(new Runnable() { @Override public void run() { Looper.prepare(); ToastUtils.showRoundRectToast("瀟湘劍雨-楊充"); Looper.loop(); } }).start();
- 得出的結論
- Toast也可以在子執行緒執行,不過需要手動提供Looper環境的。
- Toast在呼叫show方法顯示的時候,內部實現是通過Handler執行的,因此自然是不阻塞Binder執行緒,另外,如果addView的執行緒不是Loop執行緒,執行完就結束了,當然就沒機會執行後續的請求,這個是由Hanlder的建構函式保證的。可以看看handler的建構函式,如果Looper==null就會報錯,而Toast物件在例項化的時候,也會為自己例項化一個Hanlder,這就是為什麼說“一定要在主執行緒”,其實準確的說應該是 “一定要在Looper非空的執行緒”。
- Handler的建構函式如下所示: