網站首頁 編程語言 正文
Crash
Crash是指程序閃退,導致APP不能正常使用。Crash產生的原因有很多,下面只是列舉了一些常見原因。
空指針
空指針應該是項目中最容易產生crash的情況了,舉個例子,我們獲取某個對象的屬性或方法時,這個對象為Null時,如何沒有判空,則會出現空指針異常NullPointException,所以這就要求使用對象的時候進行非空判斷,在這點,我覺得kotlin就做得很好,利用空安全可以很好地避免NullPointException。
角標越界
在使用數組或者集合的時候會出現IndexOutOfBoundsException,在根據index進行取值時,最好先判斷該索引值是否存在或者使用try-catch捕捉異常。
集合元素刪除操作
比如我們需要將集合中滿足條件的元素刪除掉
list.forEach {
if (it == 3) {
list.removeAt(it)
}
}
這樣做會引起Crash,會報ConcurrentModificationException,針對這個問題,我們可以從后面開始遍歷
for (index in list.size - 1 downTo 0) {
if (list[index] == 3) {
list.removeAt(index)
}
}
也可以使用迭代器進行遍歷刪除元素
val iterator = list.iterator()
while (iterator.hasNext()) {
val a = iterator.next()
if (a == 3) {
iterator.remove()
}
}
當多個線程同時操作某個數組時,不要進行數組的增刪改查等操作,這樣同樣也會引起相關的Crash或數據查詢不準確等問題。
異步操作后對界面元素的處理
在fragment中使用Context前最好先加上判斷isAdded判斷,特別是異步操作后使用Context,很有可能出現報錯(Fragment not attached to a context)而閃退,所有的異步回調后若要操作View,都要判斷view是否為空,否則會出現界面銷毀后View為空,空指針閃退問題。
Intent傳遞數據過大
Intent傳512K以下的數據可以正常傳遞,高于512K則會出錯,因為考慮到Intent還要包括要啟動的Activity等信息,所以實際可以傳的數據應該略小于512K。
val data = ByteArray(1024 * 1024)
val intent = Intent(this, ExpActivity::class.java)
intent.putExtra("test", data)
startActivity(intent)
這段代碼會導致Crash
?Caused by: android.os.TransactionTooLargeException: data parcel size 1049012 bytes
因為我們在Intent中攜帶的數據要從APP進程傳輸到AMS進程,再由AMS進程傳輸到目標Activity所在進程,普通的由 Zygote 孵化而來的用戶進程,所映射的Binder內存大小是不到1M,但是,在使用Intent傳遞數據時,1M并不是安全上限,因為Binder可能正在處理其它的傳輸工作。總而言之,startActivity攜帶的數據會經過Binder內核再傳遞到目標Activity中去,因為binder映射內存的限制,所以startActivity也會這個限制。
在子線程中操作UI
子線程中是不能操作UI的,如果在子線程中某個時機想要改變UI,可以使用Handler或者kotlin協程切換,需要注意的是,在子線程中也不可以操作Dialog和Toast。但是,這有個很有意思的點,舉個例子,如果你在onCreate中開啟一個子線程改變UI,會發現程序運行正常,沒報錯,像這樣
class ExpActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_exp)
val name = findViewById<TextView>(R.id.name)
Thread { name.text = "name" }.start()
}
}
但是,你延遲一秒后再操作UI,又會閃退報錯
class ExpActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_exp)
val name = findViewById<TextView>(R.id.name)
Thread {
Thread.sleep(1000)
name.text = "name"
}.start()
}
}
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
這到底是為什么呢?這個的關鍵是ViewRootImpl類,它會去檢查當前線程是不是主線程,如果不是就會拋出異常。像上面的情況,在onCreate中未延時直接操作UI不閃退,是因為此時ViewRootImpl還沒有被初始化,這個時候程序沒有去檢測當前線程是不是主線程,所以沒有拋異常。嚴格地講,在ViewRootImpl構造的時候賦值的,賦值的就是當前的Thread對象,也就是說,你ViewRootImpl在哪個線程創建的,你后續的UI更新就需要在哪個線程執行,跟是不是UI線程毫無關系。
ANR
ANR是指程序未響應,在Android系統中,AMS和WMS會檢測App的響應時間,如果App在特定時間無法響應屏幕觸摸或鍵盤輸入事件,或者特定事件沒有處理完畢,就會出現ANR。
不同Context規定的上限時間不同:
- 主線程對輸入事件5秒內沒有處理完畢。
- 主線程在執行BroadcastReceiver的onReceive()函數時10秒內沒有處理完畢。
- 主線程在Service的各個生命周期函數時20秒內沒有處理完畢。
避免ANR就要盡量避免在主線程中做耗時操作,耗時操作盡量放在子線程中。
我們可以通過/data/anr/traces.txt文件來分析ANR的產生,通過adb命令可以導出該文件,不過traces文件記錄的東西可能比較多,分析的時候需要針對性地搜索出相關記錄,該文件會記錄進程ID,包名,造成ANR的原因和產生ANR的具體行數。
原文鏈接:https://blog.csdn.net/qq_45485851/article/details/122347379
相關推薦
- 2022-05-23 C語言的動態內存分配及動態內存分配函數詳解_C 語言
- 2022-10-13 C++?auto自動類型推導規則和使用詳解_C 語言
- 2022-03-28 如何創建VS?Code?擴展插件_相關技巧
- 2022-04-01 maven的settings.xml文件中配置多個nexus倉庫
- 2022-07-21 配置nacos持久化
- 2022-04-25 C#實現簡單串口通信_C#教程
- 2022-04-20 Selenium?三種等待方式(強制等待、隱式等待、顯示等待)_python
- 2023-04-06 C語言中的多行輸入問題及說明_C 語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支