Android中的几种内存泄露情况总结

来源:互联网 发布:达德网络 编辑:程序博客网 时间:2024/05/17 01:21

Handler使用不当导致的内存泄露(用这个来作为非静态内部类造成内存泄露的代表)

  这种情况比较常见,经典的例子如下所示:     

import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.support.v7.app.AppCompatActivity;import android.widget.ImageView;import java.io.IOException;import java.io.InputStream;import java.net.MalformedURLException;import java.net.URL;import java.net.URLConnection;public class MainActivity extends AppCompatActivity {    private ImageView mImageView;    Handler handler = new Handler() {        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            if (msg.what == 1) {                mImageView.setImageBitmap((Bitmap) msg.obj);            }        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mImageView = (ImageView) findViewById(R.id.imageView);        new Thread(new Runnable() {            @Override            public void run() {                Bitmap bitmap = null;                try {                    URL url = new URL("http://img0.imgtn.bdimg.com/it/u=3527986333,3942718311&fm=21&gp=0.jpg");                    URLConnection urlConnection = url.openConnection();                    InputStream inputStream = urlConnection.getInputStream();                    bitmap = BitmapFactory.decodeStream(inputStream);                } catch (IOException e) {                    e.printStackTrace();                }                Message message = new Message();                message.what = 1;                message.obj = bitmap;                handler.sendMessage(message);            }        }).start();    }}  

  开了个线程从网络中获取资源(我这里下了张图片),下完了,通过Handler发个消息回UI线程,然后在handleMessage方法中更新UI。当然,犯这种错误,Android Studio马上会提醒,Handler那一块代码会有一块阴影,鼠标光标点在哪,左下角也会出现提示:

This Handler class should be static or leaks might occur (null)  

  处理方式嘛,提示信息也说了,要把Handler应该声明为静态类,否则内存泄露,因为在Java中非静态内部类会持有外部类的引用,而那个网络请求的线程又持有Handler的引用,所以假如此时用户按了返回键,这个Activity占用的内存本来应该可以被回收的,可是现在却不行了,于是发生了内存泄露。
  解决方法,仅仅加static是不够的,因为这样Handler类没有了外部类的引用,那么也就没法更新UI了,所以完整的解决方法如下所示:

static class MyHandler extends Handler {    WeakReference<MainActivity> mWeakReference;    MyHandler(MainActivity mainActivity) {        mWeakReference = new WeakReference<>(mainActivity);    }    @Override    public void handleMessage(Message msg) {        super.handleMessage(msg);        if (mWeakReference.get() != null) {            if (msg.what == 1) {                mWeakReference.get().mImageView.setImageBitmap((Bitmap) msg.obj);            }        }    }}  

  这样的话,Handler持有的是MainActivity的弱引用,当Activity被销毁,GC需要回收内存的时候便可以顺利回收。

静态变量导致的内存泄露

  我们知道在Java中静态变量的生命周期起始于类的加载,终止于类的释放(不过好像在哪看到Android中静态变量好像比较不稳定,不知道什么时候就会被置空的,有时间去求证下),不过不管怎么样,让一个静态变量持有Activity引用,肯定不是一个好的选择。所以可以看到在上面的例子中,虽然我们可以将ImageView设为static来在static class中进行更新,但我们并没有这样做。
  今天先写到这,下次接着写。。。。

0 0
原创粉丝点击