您的位置:首页 > 其它

Activity已销毁,创建的线程未回收问题

2017-10-09 09:47 411 查看
今天在做新模块测试时发现了一个严重的问题,当一个activity开启一个线程时,如果当前activity调用finish()函数不会关闭当前创建的线程。对于每个新建activity,如果activity中的线程发生内存泄漏。在Java中线程时垃圾回收机制的根源,也就是说,在运行系统中DVM虚拟机总会使硬件持有运行状态的进程的引用,结果导致处于运行状态的线程将永远不会回收。因此你必须为你的后台线程实现销毁逻辑。

先说下问题出现的场景,我在一个activity中创建一个线程,轮询去发送请求,正常情况下是没什么问题的,先看下问题代码:

@Override
protected 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();

}

这时看Log日志是正常打印,然后我按返回键退出当前应用,发现Log日志还在打印,问题出现了,线程被没有被回收,而且当你再次返回到应用时,会再在后台创建一个线程,两个线程同时在跑。



在Java中强制关闭线程是非安全性操作,这时我们要为自己的线程添加判断条件,相关代码如下:

private MyThread myThread;

@Override
protected 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;
}
}

@Override
protected void onDestroy() {
super.onDestroy();
myThread.close();
}

这样,当activity销毁时走destroy函数然后调用Thread的close,让线程退出轮询,保证了线程安全回收。

还有另外一个思路来让线程可以及时回收,我们知道context对象与activity是绑定的,我们可以实例application来暂存当前context与当前context进行比较,我们可以优化上面的代码,具体代码如下:

自定义application用来暂存context对象:

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;

@Override
protected 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();
}
}
}
}


大功告成。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: