2016/08/20java
最近輕微強迫症又犯了,看着編譯器上的那些帶有黃色感嘆號警告就十分難受,因而就下定決心清除我能看到的全部黃色感嘆號,通常我不會用像圖1中系統提示那些處理方法,android
我以爲那是在欺騙本身,可能在處理這些警告上有些費時,可是無論怎樣,本身開心就好,.前幾天在寫一個線程實例的時候瀏覽器
用到了Handler 來傳遞數據,我以前都是像圖2那樣寫的,圖2上已然出現了一個傲嬌的黃色感嘆號,警告的內容是 This Handler class should be static or leaks might occur (com.example.ndktest.MainActivity.1) 我把我那蹩腳英語能力和有道詞典有機統一的結合以後,籠統的明白的這句話的意思是:這個Handler 類應該是靜態的,不然可能引發內存泄漏問題,在我很有成就感的品味被我翻譯出來的譯文的同時,我又開始蒙圈了,究竟是什麼緣由出現這樣奇葩的警告呢,我以前都是這麼寫的,歷來都沒有出現過內存泄漏的現象,那這個發生內存泄漏的機率豈不是很低,知其然而不知其因此然,苦惱數微秒以後,我就打開了瀏覽器,開始刨根問底,許久以後有了些收貨.先附上個人測試代碼ide
public class MainActivity extends Activity { public TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = (TextView) findViewById(R.id.tv); } Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { tv.setText("我收到了message"); }; }; }
根據代碼能夠看出 handler 是一個內部類,內部類分兩種,一種是普通內部類,也就是像上面代碼裏handler這個類那樣,另外一種是加static關鍵字的靜態內部類,就是那段警告所說的改正後的類的類型.普通內部類隱含保存了外部類的引用,靜態內部類就不是這樣了,靜態內部類只能訪問外部類的靜態成員.那這跟內存泄漏有什麼關係呢,其實思考到這裏,答案就已經很明朗了,關鍵點就在於普通內部類隱含保存了外部類的引用,若是我在上面代碼的oncreate函數裏添加finish()方法以後,在運行到finish()後,本應該進行對MainActivity 垃圾回收的,可是因爲handler內部類有對MainActivity 的引用,因此是MainActivity 對象是不會被回收的,這就形成了內存的泄漏.要解決這樣的問題,就要用到弱引用,在垃圾回收器線程掃描它所管轄的內存區域的過程當中,一旦發現了只具備弱引用的對象,就會回收它的內存,不會考慮內存的充足與否。這樣就解決了內存泄漏問題函數
改後的代碼測試
public class MainActivity extends Activity { public TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = (TextView) findViewById(R.id.tv); } // Handler handler = new Handler() { // // public void handleMessage(android.os.Message msg) { // // tv.setText("我收到了message"); // // }; // }; MyHandler handler = new MyHandler(this); static class MyHandler extends Handler { WeakReference<MainActivity> mActivity; public MyHandler(MainActivity activity) { mActivity = new WeakReference<MainActivity>(activity); } @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg); MainActivity a = mActivity.get(); if (a != null) { a.tv.setText("我收到了message"); } } } }