android内存泄漏快速解决——内部类改为静态类

在内存泄漏的解决中,内部类(案例为:匿名内部类)改成静态类绝对是一大杀器。比这曾经在一个项目中用这种方法,解决了百分之70的泄漏。解决方案简单粗暴

1)就是将匿名内部类改写为静态类,并添加弱引用

问题代码:(我使用阿里热修复的时候的代码):

SophixManager.getInstance().setPatchLoadStatusStub(new PatchLoadStatusListener() {

            @Override

            public void onLoad(final int mode, final int code, final String info, final int handlePatchVersion) {
              //todo something
              }
})

使用LeakCanranry,直接报泄漏,泄漏日志显示“是PatchLoadStatusListener 持有acitivity 引用”
这个案例是在首页做的,只要一按下返回键,必现泄漏。

处理方法就是改写为:

private static class MyPatchLoadStatusListener  implements PatchLoadStatusListener {

private WeakReferenceweakReference;

    public MyPatchLoadStatusListener(HomeActivity homeActivity) {

weakReference =new WeakReference<>(homeActivity);

    }

@Override

    public void onLoad(int i, int code, String s, int i2) {

}

}

调用的地方修改为:

SophixManager.getInstance().setPatchLoadStatusStub(new MyPatchLoadStatusListener(this));

修正后,leakcananry 不再报错。开发中养成良好的习惯,坚决不写有泄漏的代码

2)内部类改成外部类,并添加弱引用

开发一个倒计时splash页面,之后进入应用。在进入的时候,发现leakCananry报泄漏。日志如下:

内部类持有外部类的引用

重点看哪里呢,重点看紫色实线和虚线的交叉处,如果只有虚线,直接从虚线底端看起


观察如上部分

这里表明了,是匿名内部类TimeTask持有引用了ActivityAdvertising ,导致我们出现了泄漏:
找到代码:

public class ActivityAdvertising extends MyActivity {
.....
  ScheduledExecutorService newScheduledThreadPool = Executors
            .newScheduledThreadPool(1);
    private int time;
    TimerTask timerTask = new TimerTask() {
        @Override
        public void run() {
            runOnUiThread(() -> {
                time--;
                if (countdownProgressView != null) {
                    touch_ok.setClickable(false);
                    countdownProgressView.setText(time + "s");
                }
                if (time <= 0) {
                    if (countdownProgressView != null) {
                        countdownProgressView.setText("進入");
                        touch_ok.setClickable(true);
                    }
                }
            });
        }
    };
}
....

一看代码,高危呀,匿名内部类。 处理成外部类问题解决:


public class Ttimetask extends TimerTask {
    public WeakReference weakReference;
    public Ttimetask(ActivityAdvertising activityAdvertising){
       weakReference =new WeakReference(activityAdvertising);
    }
    @Override
    public void run() {
        weakReference.get().runTimeTask();
    }
}

调用的地方:


class ActivityAdvertising : MyActivity() {
 
    internal var newScheduledThreadPool = Executors
        .newScheduledThreadPool(1)
    private var time: Int = 0

    var timerTask=Ttimetask(getActivity())
    fun runTimeTask(){
        runOnUiThread {
            time--
            if (countdownProgressView != null) {
                touch_ok!!.isClickable = false
                countdownProgressView!!.text = time.toString() + "s"
            }
            if (time <= 0) {
                if (countdownProgressView != null) {
                    countdownProgressView!!.text = "進入"
                    touch_ok!!.isClickable = true
                }
            }
        }
    }
   
    override fun initView() {
        timerTask.run()

    }

    fun cancelTimer() {
        if (timerTask != null) {
            timerTask.cancel()
        }
    }


    override fun initData() {       
        time = 5
        newScheduledThreadPool.scheduleAtFixedRate(timerTask, 0, 1000, TimeUnit.MILLISECONDS)     

    } 

    override fun onDestroy() {
        super.onDestroy()
        cancelTimer()
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)       
    }

}

一个timeTask泄漏就解决掉了:网上很多人说是需要添加 TimeTask的取消方法,kotlin版本下我的代码实测没有通过,我是通过外部类的方法解决掉的:


微信图片_20200304143258.png

再次点击,leakCanary下,测试了一大波,还是只有Audiodmanager的泄漏,timeTask泄漏顺利解决。

Android内存泄漏解决(总)

你可能感兴趣的:(android内存泄漏快速解决——内部类改为静态类)