【问题标题】:Android Memory Leak, no static variablesAndroid内存泄漏,没有静态变量
【发布时间】:2012-05-21 03:37:10
【问题描述】:

我是一名初级Android开发人员,作为一个实践项目,我正在尝试制作一个可以拍照的活动,将其保存到外部存储中,并将其显示在ImageView中。几乎一切似乎都在工作,但是,我似乎有内存泄漏。

当屏幕方向改变时,我相信活动被破坏,然后重新创建。为了继续显示图像,我将图像的路径作为字符串存储在 onSaveInstanceState 中的包中,并在 onResotreInstanceState 中重置图像。拍摄 5mp 图片,我可以旋转一次屏幕,然后在第二次旋转时,应用程序崩溃,LogCat 报告内存不足错误。使用较低分辨率的图像,我得到更多的旋转,但应用程序最终仍然崩溃并且我得到同样的错误。

我一直在阅读有关 android 内存泄漏的信息,所有内容似乎都在说不要使用静态 Drawable,它可以引用视图,并防止 vm 释放内存。据我所知,我不会做这样的事情来保持引用。如果有人可以帮助我找到我的错误,我将不胜感激。代码如下:

public class CameraTestsActivity extends Activity {

private Uri fileUri;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
}

public void takePicture(View view){
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

    fileUri = getOutputImageFileUri();
    intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);

    startActivityForResult(intent, 0);
}

private static Uri getOutputImageFileUri() {
    return Uri.fromFile(getOutputImageFile());
}

private static File getOutputImageFile(){
    Log.d("CameraTestsActivity", "Storage state: " + Environment.getExternalStorageState());
    if (Environment.getExternalStorageState().equals("mounted")){
        File mediaStorageDirs = new File (Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures" + "/CameraTestsActivity");
        if (! mediaStorageDirs.exists()){
            if (! mediaStorageDirs.mkdirs()){
                Log.d("CameraTestsActivity", "Failed to create directories");
                mediaStorageDirs = null;
                return null;
            }
        }

        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        File imageFile = new File(mediaStorageDirs.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");
        mediaStorageDirs = null;
        return imageFile;


    }
    Log.d("CameraTestsActivity", "Storage state bad");
    return null;
}



@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == RESULT_OK){
        if (requestCode == 0){
            setImage();
        }
    }
    else{
        super.onActivityResult(requestCode, resultCode, data);
    }
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    fileUri = Uri.parse(savedInstanceState.getString("uri"));
    setImage();
    super.onRestoreInstanceState(savedInstanceState);
}

@Override
protected void onSaveInstanceState(Bundle outState) {
    outState.putString("uri", fileUri.toString());
    super.onSaveInstanceState(outState);
}

private void setImage(){
    ImageView image = (ImageView)findViewById(R.id.imageView1);
    File file = new File(fileUri.toString().substring(7));
    if (!file.exists())
        Log.d("CameraTestsActivity", "File " + fileUri.toString().substring(7) + "does not exist");
    image.setImageURI(fileUri);
}

}

【问题讨论】:

    标签: android image memory-leaks android-activity screen-orientation


    【解决方案1】:

    在显示位图时,我们应该注意它的大小不要超过堆大小或虚拟机预算。 尽管您没有任何内存泄漏,但是当您更改方向时,可能需要一些时间来清理以前加载的位图,因此您会遇到内存溢出错误。 为避免此错误,请阅读此How to display bitmap efficiently

    【讨论】:

    • 谢谢,这真的很有帮助。我意识到只有在我快速来回转动设备时它才会崩溃——如果我慢慢地转动它,它并没有耗尽内存,这让我认为 GC 在我需要的时候没有发生,并且图像太大,无法如此快速地处理。我会继续使用它,但缩放图像似乎真的很有帮助。
    • 关于位图,在 API 10-(蜂窝以下)上,您应该调用 recycle() 。否则,操作系统应该处理好位图并为您释放它。
    【解决方案2】:

    尝试分析您应用的内存以找出泄漏点,这里有一些链接:link1link2

    您也可以尝试手动释放以前的 Activity 的位图,方法是从 ImageView 中删除它并在调用 Activity 的 onStop() 时调用 Bitmap.recycle(),因为在 Honycomb 之前,可以释放位图的后备缓冲区的时间相当长不确定的。

    【讨论】:

    • 谢谢,我之前看过第一个链接,但第二个确实帮助我完成了所有设置以检查堆。最终,看起来并没有真正的泄漏,因为如果我不经常旋转,就没有问题。现在我在加载之前缩放图像,问题完全消失了 - 我不再看到 DDMS 中的堆大小不断增加。
    猜你喜欢
    • 2013-11-06
    • 2014-12-06
    • 1970-01-01
    • 2012-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-29
    • 1970-01-01
    相关资源
    最近更新 更多