首页 > 学院 > 开发设计 > 正文

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

2019-11-09 14:08:15
字体:
来源:转载
供稿:网友

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

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

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

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

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();}这样,当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;@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();            }        }    }}

大功告成。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表