您的位置:首页 > 其它

Activity声明周期容易出现的问题

2015-07-18 21:36 253 查看
了解activity的生命周期,不仅仅是回答面试官的几个小问题:下面这篇文章不错,截取个人认为优秀的部分分享给大家,欢迎交流.感谢原作者

/**
*  示例向我们展示了在 Activity 的配置改变时(配置改变会导致其下的 Activity 实例被销
*  毁)存活。此外,Activity 的 context 也是内存泄漏的一部分,因为每一个线程都被初始
*  化为匿名内部类,使得每一个线程都持有一个外部 Activity 实例的隐式引用,使得
*  Activity 不会被 Java 的垃圾回收机制回收。
*/
public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
exampleOne();
}

private void exampleOne() {
new Thread() {
@Override
public void run() {
while (true) {
SystemClock.sleep(1000);
}
}
}.start();
}
}

Activity 配置发生改变会使 Activity 被销毁,并新建一个 Activity,我们总会觉得 Android 系统会将与被销毁的 Activity 相关的一切清理干净,例如回收与 Activity 关联的内存,Activity 执行的线程等等……然而,现实总是很残酷的,刚刚提到的这些东西都不会被回收,并导致内存泄漏,从而显著地影响应用的性能表现。

Activity 内存泄漏的根源

每一次配置的改变都会使 Android 系统新建一个 Activity 并把改变前的 Activity 交给垃圾回收机制回收。但因为线程持有旧 Activity 的隐式引用,使该 Activity 没有被垃圾回收机制回收。

我们把该线程类声明为私有的静态内部类就可以解决这个问题:

/**
* 示例通过将线程类声明为私有的静态内部类避免了 Activity context 的内存泄漏问题,但
* 在配置发生改变后,线程仍然会执行。原因在于,DVM 虚拟机持有所有运行线程的引用,无论
* 这些线程是否被回收,都与 Activity 的生命周期无关。运行中的线程只会继续运行,直到
* Android 系统将整个应用进程杀死
*/
public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
exampleTwo();
}

private void exampleTwo() {
new MyThread().start();
}

private static class MyThread extends Thread {
@Override
public void run() {
while (true) {
SystemClock.sleep(1000);
}
}
}
}


通过上面的代码,新线程再也不会持有一个外部 Activity 的隐式引用,而且该 Activity 也会在配置改变后被回收。

下面是一种解决办法:

/**
* 除了我们需要实现销毁逻辑以保证线程不会发生内存泄漏,其他代码和示例2相同。在退出当前
* Activity 前使用 onDestroy() 方法结束你的运行中线程是个不错的选择
*/
public class MainActivity extends Activity {
private MyThread mThread;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
exampleThree();
}

private void exampleThree() {
mThread = new MyThread();
mThread.start();
}

/**
* 私有的静态内部类不会持有其外部类的引用,使得 Activity 实例不会在配置改变时发生内
* 存泄漏
*/
private static class MyThread extends Thread {
private boolean mRunning = false;

@Override
public void run() {
mRunning = true;
while (mRunning) {
SystemClock.sleep(1000);
}
}

public void close() {
mRunning = false;
}
}

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


通过上面的代码,我们在 onDestroy() 方法中结束了线程,确保不会发生意外的线程的内存泄漏问题。如果你想要在配置改变后保留该线程(而不是每一次在关闭 Activity 后都要新建一个线程),那我建议你使用 Fragment 去完成该耗时任务。百度一篇叫作“Handling Configuration Changes with Fragments”应该能满足你的需求,在API demo中也提供了很好理解的例子来为你阐述相关概念。

在Activity中使用Thread导致的内存泄漏



原文链接 : Activitys, Threads, & Memory Leaks

原文作者 : AlexLockwood

译文出自 : 开发技术前线 www.devtf.cn

译者 : chaossss

校对者: yinna317

状态 : 完成

注:这篇博文涉及的源码可以在 GitHub 上面下载哦

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