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

了解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导致的内存泄漏

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

原文地址:https://www.cnblogs.com/yizuochengchi2012/p/4657744.html