先介绍下WeakReference
WeakReference在java中被称为弱引用,其父类为Reference,其兄弟还有强引用,软应用,虚引用.一般强引用指向的对象java虚拟机是
不会主动回收的(除非java虚拟机判断该引用对象不再使用了,例如在某个方法中的局部变量,引用会从方法栈出弹出),而弱引用不一样,其回
收时机是下一次java发生gc动作时(此时没有其他的强引用指向它,并且该强应用发生过使用,待会再做出说明).所以,弱引用可以做一些调配缓存,适用于一些消耗比较大的对象,可以提高程序的性能.需要注意的是,在调用weakreference的get方法时一定要做判空动作,否则很容易造成空指针异常.
WeakReference使用示例代码
写个pojo类型对象
public class TV {
private String price;
private String band;
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getBand() {
return band;
}
public void setBand(String band) {
this.band = band;
}
}
调用WeakReference
public class Client {
public static void main(String[] args) {
TV tv = new TV();
tv.setPrice("2000");
tv.setBand("海尔");
WeakReference<TV> reference = new WeakReference<TV>(tv);
while (true) {
if (reference.get() == null) {
System.out.println("对象被回收了");
break;
}else {
System.out.println("对象还存在");
}
}
}
}
打印结果
对象还存在
对象还存在
对象还存在
对象还存在
对象还存在
对象还存在
对象还存在
对象还存在
对象被回收了
这里说明对象确实在一段时间后就被回收了.
假如这个TV对象被其它强引用引用了呢,试一下.代码修改一下,如下:
public class Client {
private static TV mTV;
public static void main(String[] args) {
TV tv = new TV();
mTV = tv;
tv.setPrice("2000");
tv.setBand("海尔");
WeakReference<TV> reference = new WeakReference<TV>(tv);
while (true) {
if (reference.get() == null) {
System.out.println("对象被回收了");
break;
}else {
System.out.println("对象还存在");
}
}
}
}
修改后,Log打印根本停不下来:
对象还存在
对象还存在
对象还存在
对象还存在
对象还存在
对象还存在
对象还存在
对象还存在
再修改下,假如没有其他的强引用指向它,这里tv本身就是一个强引用,再在while循环里面使用下这个tv对象试试看,代码修改如下:
public class Client {
public static void main(String[] args) {
TV tv = new TV();
tv.setPrice("2000");
tv.setBand("海尔");
WeakReference<TV> reference = new WeakReference<TV>(tv);
while (true) {
System.out.println(tv.getPrice());
if (reference.get() == null) {
System.out.println("对象被回收了");
break;
}else {
System.out.println("对象还存在");
}
}
}
}
修改后,Log也同样根本停不下来:
对象还存在
2000
对象还存在
2000
对象还存在
2000
对象还存在
2000
所以这两个修改印证了刚刚的说法.
那么在Android中这个WeakReference哪里又可以用到呢?
我们经常在Android中用到一个类叫做Handler,这个是很熟悉的一个类,它具有发送消息,处理消息,主线程切换等功能.那么在java
中,我们也知道非静态内部类匿名的存在一个对外部类的引用.而我们经常把Handler定义在Activity中,这样就会导致handler中的消息
没处理或者没处理完,导致Activity被关闭无法得到有效的释放.假如在studio中这么使用,系统会提示你把handler定义成一个静态内部
类,这个说明Google也是不希望我们这么做的.
诸如下面的代码所示,会导致内存泄露:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
// and do something
}
},2000);
finish();
}
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
//do something......
}
};
}
此时的MainActivity就得不到有效的回收
那么该怎么做呢?此时WeakReference就派上用场了,我们一样把Handler定义成成员变量,只不过是静态的,此时就不会含有匿名的
Activity引用了.但是handler中一般要处理Activity中的业务逻辑,所以需要一个weakreference弱引用指向他,用于调用Activity中
当前存在的逻辑方法.但是要注意,记得判空动作.
示例代码如下:
public class MainActivity extends Activity {
private TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.tv_text);
}
private static class MyHandler extends Handler {
private WeakReference<MainActivity> reference;
public MyHandler(MainActivity activity) {
reference = new WeakReference<MainActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
//do something......
MainActivity activity = reference.get();
if(activity != null){
activity.mTextView.setText("哈哈哈");
}
}
}
}
好了,关于WeakReference的讨论就到这里了,下篇写一篇关于WeakHashMap的讨论和实际应用.