• Handler引起的内存泄露


    一般我都写handler的时候是这样的:

     
    public class MyActivity extends Activity{
       private final Handler myHandler = new Handler(){
           public void handleMessage(Message msg){
              //。。。。
          }  
     
       };
    }
    

      

     
    但是这样会引起内存泄露。。。 为什么会呢?
     
    1. Android 启动时会自动创建主线程使用的Looper实例,Looper的主要工作是一个一个的处理队列中消息的。在android中,所有的android框架事件(eg:activity生命周期方法和点击事件方法)都是放到消息中,然后加入Looper要处理的消息队列中,由Looper负责一条一条的处理,Loope的生命周期和应用程序一样长.
    2. 当一个handler在主线程初始化后,我们发送一个target为handler的消息到Looper处理的消息队列中,是个消息是包含了一个Handler的实例引用的,只有包含了一个实例引用才可以再消息中调用Handler#handlerMessage(Meaasge msg)完成消息的正确处理。
    3、在Java中非静态的内部类和匿名内部类都会隐式的持有外部类的引用静态的内部类不会持有外部类的应用。
     
    上面方法:Loopr ->myHandler->MyActivity ->持有各种资源
     
    我们假设myHandler是一个延迟处理的比如下面:
     
    public class MyActivity extends Activity{ 
     private final Handler myHandler =newHandler(){
      @Override
      public void handleMessage(Messagemsg){
       // ...
     }
    }
    @Override
    protected void onCreate(BundlesavedInstanceState){
          super.onCreate(savedInstanceState);// 发送一个延迟十分钟的消息
          mLeakyHandler.postDelayed(newRunnable(){@Overridepublicvoidrun(){/* ... */}},1000*60*10);
      // 然后结束当前页面
      finish();
     }
    }
    

      

    我们执行了Activity的finish方法,被延迟的消息会在被处理之前存在于主线程消息队列中10分钟,而这个消息中又包含了Handler的引用,而Handler是一个匿名内部类的实例,其持有外面的MyActivity 的引用,所以这导致了MyActivity 无法回收,进行导致MyActivity 持有的很多资源都无法回收,这就是我们常说的内存泄露。
    如何解决呢???
    思路就是避免使用非静态内部类。
    继承Handler时
      1.放在单独的类文件中。。
      2.使用静态内部类。 因为静态内部类不会持有外部类的引用,就不会导致外部类实例的内存泄露。
    当你需要在静态内部类中调用外部的Activity时,我们可以使用弱引用来处理。另外关于同样也需要将Runnable设置为静态的成员属性。
    public class 
    MyActivity 
    extends Activity {
    
    /**   * Instances of static inner classes do not hold an implicit   
          * reference to their outer class.   
          */
    private static class MyHandler extends Handler{
      private final WeakReference<SampleActivity> mActivity;
      public MyHandler(SampleActivityactivity){
         mActivity=newWeakReference<SampleActivity>(activity);
      }
     @Override public void handleMessage(Messagemsg){
      SampleActivityactivity=mActivity.get();
      if(activity!=null){
      // ...}
      }
     }
    private final MyHandler mHandler=newMyHandler(this);
    /** 
      * Instances of anonymous classes do not hold an implicit
       * reference to their outer class when they are "static".  
      */
    private static final Runnables Runnable=newRunnable(){
     @Override
    public void run(){
     /* ... */
    }
    };
     @Override 
    protected void onCreate(BundlesavedInstanceState){
    super.onCreate(savedInstanceState);
    // Post a message and delay its execution for 10 minutes.
     mHandler.postDelayed(sRunnable,1000*60*10);
    // Go back to the previous
     Activity.finish();
    }
    }
    

      

     
     
    其实在Android中很多的内存泄露都是由于在Activity中使用了非静态内部类导致的,就像本文提到的一样,所以当我们使用时要非静态内部类时要
    格外注意,如果其实例的持有对象的生命周期大于其外部类对象,那么就有可能导致内存泄露。个人倾向于使用文章的静态类和弱引用的方法解决这种问题。
  • 相关阅读:
    spring学习(一)IOC&AOP
    MongoDB 写入数据的安全性
    MongoDB MapReduce
    MongoDB 原子操作
    MongoDB 文档间的关系
    MongoDB Java
    MongoDB 持久化
    MongoDB 聚合函数 aggregate
    MongoDB 索引
    MongoDB 文档操作
  • 原文地址:https://www.cnblogs.com/sjm19910902/p/6386554.html
Copyright © 2020-2023  润新知