android-内部类导致的内存泄漏实战解析

参考:
Android 如何有效的解决内存泄漏的问题
Java-内部类的相关知识
Android-LeakCanary检测内存泄漏

非静态内部类: 成员内部类, 局部内部类、 匿名内部类。 会有对外部类的引用。这样内部类中耗时操作在用户频繁退出重启APP相关Activity时很容易导致内存泄漏。

一、匿名内部类:Runnable

1、泄漏版

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //模拟耗时操作
                    Thread.sleep(15000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

连续多次退出重启后发现:

这里写图片描述

2、优化版:

将 非静态内部类 改为 静态非匿名内部类

  new Thread(new MyRunnable()).start();


  private static class MyRunnable implements Runnable {

        @Override
        public void run() {
            try {
                Thread.sleep(15000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

二、成员内部类:Handler

1、泄漏版:

   private final static int MESSAGECODE = 1;

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Log.d("mmmmmmmm", "handler " + msg.what);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new Thread(new Runnable() {
            @Override
            public void run() {
                handler.sendEmptyMessage(MESSAGECODE);
                try {
                    Thread.sleep(8000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                handler.sendEmptyMessage(MESSAGECODE);
            }
        }).start();


    }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

连续多次退出重启后发现:

这里写图片描述

2、优化版:

2.1、使用静态内部类
2.2、使用弱引用
2.3、在onDestroy() 里面取消异步任务。(注意:单纯的取消还是会内存泄漏)

    private final static int MESSAGECODE = 1;
    private static Handler handler;//静态

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //创建Handler
        handler = new MyHandler(this);

        //创建线程并且启动线程
        new Thread(new MyRunnable()).start();
    }


    //1、避免Handler引用activity造成的内存泄漏:使用静态内部类+ 使用弱引用
    private static class MyHandler extends Handler {
        WeakReference<HandlerActivity> weakReference;

        public MyHandler(HandlerActivity activity) {
            weakReference = new WeakReference<HandlerActivity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (weakReference.get() != null) {
                // update android ui
                Log.d("mmmmmmmm", "handler " + msg.what);
            }
        }
    }

    //2、避免非静态Runnable内部类引用activity造成的内存泄漏
    private static class MyRunnable implements Runnable {

        @Override
        public void run() {
            handler.sendEmptyMessage(MESSAGECODE);
            try {
                Thread.sleep(8000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            handler.sendEmptyMessage(MESSAGECODE);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //3、如果参数为null的话,会将所有的Callbacks和Messages全部清除掉。
        handler.removeCallbacksAndMessages(null);
    }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

三、匿名内部类:TimerTask

1、泄漏版:

        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                while (true) ;
            }
        }, 1000);  // 1秒后启动一个任务
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

连续多次退出重启后发现:

这里写图片描述

2、优化版:

1、在适当的时机进行Cancel。
2、TimerTask用静态内部类

 private TimerTask timerTask ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        timerTask = new MyTimerTask() ;
        new Timer().schedule( timerTask ,1000 );  // 1秒后启动一个任务
    }


    private static class MyTimerTask extends TimerTask {

        @Override
        public void run() {
            while(true){
                Log.d( "ttttttttt" , "timerTask" ) ;
            }
        }
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        //取消定时任务
        if ( timerTask != null ){
            timerTask.cancel() ;
        }

    }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

四、匿名内部类:AsyncTask

1、泄露版:

new AsyncTask<String,Integer,String>(){

            @Override
            protected String doInBackground(String... params) {
                try {
                    Thread.sleep( 6000 );
                } catch (InterruptedException e) {

                }
                return "ssss";
            }


            @Override
            protected void onPostExecute(String s) {
                super.onPostExecute(s);
                Log.d( "mmmmmm activity2 " , "" + s ) ;
            }

}.execute();
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

连续多次退出重启后发现:

这里写图片描述

2、优化版

1、自定义静态AsyncTask类
2、AsyncTask的周期和Activity周期应该保持一致。也就是在Activity生命周期结束时要将AsyncTask cancel掉。

    private static MyTask myTask;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myTask = new MyTask();
        myTask.execute();
    }

    //1、创建静态内部类
    private static class MyTask extends AsyncTask {

        @Override
        protected Object doInBackground(Object[] params) {
            try {
                //模拟耗时操作
                Thread.sleep(15000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "";
        }
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        //2、取消异步任务
        if (myTask != null) {
            myTask.cancel(true);
        }
    }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

转自:https://blog.csdn.net/sinat_31057219/article/details/74533647

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值