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

今天在做新模块测试时发现了一个严重的问题,当一个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();
            }
        }
    }
}

大功告成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值