今天是我注冊簡書的第一天斥黑,我是一個Android程序員揖盘。剛開始做這一行時就有很多前輩和我說,作為一個技術(shù)人員要堅持每天寫博客锌奴,把自己工作中遇到的問題記下來兽狭。我曾經(jīng)也在其他平臺寫過幾篇,但都沒有堅持下去鹿蜀。最近在工作中遇到的一些事情讓我覺得很難過箕慧,在和同事討論一個技術(shù)方案時發(fā)現(xiàn)在表達(dá)自己的觀點(diǎn)時邏輯混亂,總是無法讓同事理解我的想法茴恰。我曾經(jīng)一度以為是同事的理解能力差颠焦,直到我遇到好幾次這樣的事情,才讓我不得不思考是不是我自己的問題往枣?越在職場中混跡越讓我覺得表達(dá)自己的觀點(diǎn)并且讓別人理解是一種很重要的能力伐庭。為此我決定從今天開始重新開始寫博客,既可以把自己在工作中遇到的事情記錄下來分冈,又可以鍛煉自己的表達(dá)能力圾另,如果同時能對別人有幫助就再好不過了。現(xiàn)在開始進(jìn)入主題吧雕沉。
今天先來說說我關(guān)于內(nèi)存泄漏的看法盯捌,在網(wǎng)上有很多介紹避免內(nèi)存泄漏的方法,這里就不在贅述了蘑秽。我想說的是饺著,如果在我們的app中不幸發(fā)生了內(nèi)存泄漏該怎么辦呢箫攀?有沒有什么辦法補(bǔ)救呢?隨著業(yè)務(wù)越來越復(fù)雜幼衰,代碼越來越多靴跛,以及人員的更替,哪怕編程過程中再仔細(xì)渡嚣,靜態(tài)代碼檢查再嚴(yán)格梢睛,也總是有落網(wǎng)之魚的。
在debug的App中絕大多數(shù)App都會使用LeakCanary來檢測內(nèi)存泄漏识椰,它的實(shí)現(xiàn)原理是監(jiān)聽activity的生命周期,在activity的onDestory方法中創(chuàng)建一個虛引用指向這個activity對象藏畅。五分鐘過后通過虛引用的get方法判斷activity對象有沒有被銷毀掉功咒,如果沒有被銷毀手動觸發(fā)gc,再用同樣的方式判斷一下榜旦,如果還是沒有被銷毀就dump memory景殷,并且發(fā)送內(nèi)存泄漏通知。在我們的正式版的app中是否也可以用這種方試來監(jiān)聽內(nèi)存泄漏呢猿挚?在發(fā)生內(nèi)存泄漏時做點(diǎn)什么,讓內(nèi)存泄漏的造成的代價最小。對于一個activity而言最占用內(nèi)存的部分就是它持有的view對象梁厉,因?yàn)関iew對象中可能包含很多圖片作為背景或者其他的。還有就是業(yè)務(wù)相關(guān)的對象八秃。那么在監(jiān)聽到某個activity發(fā)生內(nèi)存泄漏后我們就可以釋放activity持有的view對象以及其他的對象肉盹。可以通過反射骤肛,也可以通過創(chuàng)建一個接口,里面包含一個trimMemory之類的方法用于在發(fā)生內(nèi)存泄漏時釋放activity引用的對象腋颠。簡單實(shí)現(xiàn)如下
MemoryLeak.kt
class MemoryLeakAppliction : Application() {
private val mHandler = Handler(Looper.getMainLooper())
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
override fun onActivityPaused(p0: Activity) {
}
override fun onActivityStarted(p0: Activity) {
}
override fun onActivityDestroyed(p0: Activity) {
val activityReference = WeakReference(p0)
mHandler.postDelayed({
Looper.myQueue().addIdleHandler {
if (activityReference.get() == null) {
Log.i(TAG, "good!!! has not memory leak")
return@addIdleHandler false
}
Log.i(TAG, "may be memory leak!!, gc and check 3 seconds latter")
System.gc()
mHandler.postDelayed({
val activity = activityReference.get()
if (activity != null) {
Log.w(TAG, "memory leak!!! activity = ${activity.javaClass.name}")
if (activity is MemoryLeakCallbck) {
activity.onMemoryLeak()
}
}
}, 3 * 1000)
return@addIdleHandler false
}
}, 5 * 60 * 1000)
}
override fun onActivitySaveInstanceState(p0: Activity, p1: Bundle) {
}
override fun onActivityStopped(p0: Activity) {
}
override fun onActivityCreated(p0: Activity, p1: Bundle?) {
}
override fun onActivityResumed(p0: Activity) {
}
})
}
}
interface MemoryLeakCallbck {
fun onMemoryLeak()
}
MemoryLeakTestActivity.kt
package com.example.firstapp
import androidx.appcompat.app.AppCompatActivity
class MemoryLeakTestActivity: AppCompatActivity(), MemoryLeakCallbck {
override fun onMemoryLeak() {
//如果發(fā)生內(nèi)存泄漏巾腕,釋放activity引用的對象
setContentView(null)
}
}