今天在做新模塊測(cè)試時(shí)發(fā)現(xiàn)了一個(gè)嚴(yán)重的問(wèn)題,當(dāng)一個(gè)activity開(kāi)啟一個(gè)線程時(shí),如果當(dāng)前activity調(diào)用finish()函數(shù)不會(huì)關(guān)閉當(dāng)前創(chuàng)建的線程。對(duì)于每個(gè)新建activity,如果activity中的線程發(fā)生內(nèi)存泄漏。在java中線程時(shí)垃圾回收機(jī)制的根源,也就是說(shuō),在運(yùn)行系統(tǒng)中DVM虛擬機(jī)總會(huì)使硬件持有運(yùn)行狀態(tài)的進(jìn)程的引用,結(jié)果導(dǎo)致處于運(yùn)行狀態(tài)的線程將永遠(yuǎn)不會(huì)回收。因此你必須為你的后臺(tái)線程實(shí)現(xiàn)銷毀邏輯。
先說(shuō)下問(wèn)題出現(xiàn)的場(chǎng)景,我在一個(gè)activity中創(chuàng)建一個(gè)線程,輪詢?nèi)グl(fā)送請(qǐng)求,正常情況下是沒(méi)什么問(wèn)題的,先看下問(wèn)題代碼:
@OverridePRotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new Thread(new Runnable() { @Override public void run() { while (1 == 1) { try { Thread.sleep(1000); Log.i("-------", "running"); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start();}這時(shí)看Log日志是正常打印,然后我按返回鍵退出當(dāng)前應(yīng)用,發(fā)現(xiàn)Log日志還在打印,問(wèn)題出現(xiàn)了,線程被沒(méi)有被回收,而且當(dāng)你再次返回到應(yīng)用時(shí),會(huì)再在后臺(tái)創(chuàng)建一個(gè)線程,兩個(gè)線程同時(shí)在跑。在Java中強(qiáng)制關(guān)閉線程是非安全性操作,這時(shí)我們要為自己的線程添加判斷條件,相關(guān)代碼如下:
private MyThread myThread;@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myThread = new MyThread(); myThread.start();}private class MyThread extends Thread { private boolean stop = false; @Override public void run() { super.run(); while (!stop) { try { Thread.sleep(1000); Log.i("-------", "running"); } catch (InterruptedException e) { e.printStackTrace(); } } } public void close() { stop = true; }}@Overrideprotected void onDestroy() { super.onDestroy(); myThread.close();}這樣,當(dāng)activity銷毀時(shí)走destroy函數(shù)然后調(diào)用Thread的close,讓線程退出輪詢,保證了線程安全回收。還有另外一個(gè)思路來(lái)讓線程可以及時(shí)回收,我們知道context對(duì)象與activity是綁定的,我們可以實(shí)例application來(lái)暫存當(dāng)前context與當(dāng)前context進(jìn)行比較,我們可以優(yōu)化上面的代碼,具體代碼如下:
自定義application用來(lái)暫存context對(duì)象:
public class MyApplication extends Application { static Context appContext; @Override public void onCreate() { super.onCreate(); } public static void setContext(Context context) { appContext = context; }}讓線程去做context比較,這樣我們就可以忽略activity的生命周期:private MyThread myThread;@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MyApplication.setContext(this); myThread = new MyThread(this); myThread.start();}private class MyThread extends Thread { private boolean stop = false; private Context context; public MyThread(Context context) { this.context = context; } @Override public void run() { super.run(); while (context == MyApplication.appContext) { try { Thread.sleep(1000); Log.i("-------", "running"); } catch (InterruptedException e) { e.printStackTrace(); } } }}大功告成。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注