对Java接口回调的一些内存泄漏优化的想法

在日常开发中,对于异步的访问,JAVA端都习惯通过Interface来构建回调通知,而在线程处理方面,Interface的回调一般都会与回调需要处理的API在相同线程,一般为UI线程,但回调需要调用宿主的相关API处理,这就需要调用宿主的引用,如果回调的Interface还在调用的队列里面没有用到,但宿主已经结束使命,准备回收,Interface由于内含宿主的应用,就比较容易导致内存泄漏,例子如下:

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
//定义接口
public interface InnetCallBack {
void showData(int data);
}

//main.java
public class Main {

public static void main(String[] args) {
// TODO Auto-generated method stub

}

private String nameString;

private int age;

String funString;

private InnetCallBack mCallBack = new InnetCallBack() {

@Override
public void showData(int data) {
// TODO Auto-generated method stub
System.out.print("Hello world");
}
};

}

main.java通过编译成class文件后,对于其内部类mCallBack会生成文件名Main$1.class,代码如下:

1
2
3
4
5
6
7
8
9
class Main$1 implements InnetCallBack {
Main$1(Main var1) {
this.this$0 = var1;
}

public void showData(int data) {
System.out.print("Hello world");
}
}

从生成的代码看出其内部类会在构造函数自动引用其宿主类的强引用,如果该内部类使用不当,极易导致内存泄漏,目前的一些想法是:
1、内部类如果是非静态类,其构造函数默认会引用宿主的强引用,对应的解决方案是把内部类定义为静态内部类

2、静态内部类不可以调用宿主的任何方法,通过弱引用WeakReference在构造函数引进宿主的引用

3、为了不破坏原有类的封闭开放原则,对内部类需要调用的方法或字段使用默认的包声明

4、为适配多接口的共享宿主,抽象内部类为:

1
2
3
4
5
6
7
8
9
10
11
 /**
* Created by linzh on 2017/3/21.
* 通过创建静态内部类+弱应用方式避免内存泄漏
*/

public abstract class WeakReferenceInterface<T> {
protected WeakReference<T> mReference;

public WeakReferenceInterface(T t) {
mReference = new WeakReference<>(t);
}
}

例子代码如main1.java

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
public class Main1 {

public static void main(String[] args) {
// TODO Auto-generated method stub

}

private String nameString;

private int age;

String funString;

private CallBackImpl mCallBackImpl;

private static class CallBackImpl extends WeakReferenceInterface<Main1>
implements InnetCallBack {


public CallBackImpl(Main1 t) {
super(t);
// TODO Auto-generated constructor stub
}

@Override
public void showData(int data) {
// TODO Auto-generated method stub
System.out.print("Hello world");
mReference.get().funString = "Hello world";
}
};
}

对应的内部类CallBackImpl的class文件如下:

1
2
3
4
5
6
7
8
9
10
class Main1$CallBackImpl extends WeakReferenceInterface<Main1> implements InnetCallBack {
public Main1$CallBackImpl(Main1 t) {
super(t);
}

public void showData(int data) {
System.out.print("Hello world");
((Main1)this.mReference.get()).funString = "Hello world";
}
}

可见,对宿主的引用只剩下弱引用
以上为个人的一些想法,不妥之处敬请指正,THX~~

文章目录
,