旋转手机会导致内存的内存不足 [英] Rotating the phone causes memory out of memory

查看:148
本文介绍了旋转手机会导致内存的内存不足的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有借鉴在其他绘制的可绘制一个很简单的活动 A 画布并在年底演出它在的ImageView 。我知道,在创建位图占用太多的内存和规模下来,我知道通过保持参照上下文泄漏,但无法检测它发生在哪里。现在经过4-5次的旋转,我得到了内存不足的错误。 (我指定上code)

您能帮我找到在哪里发生泄漏?

这是我的code:

 公共类MainActivity延伸活动{    @覆盖
    保护无效的onCreate(捆绑savedInstanceState){
        super.onCreate(savedInstanceState);
        的setContentView(R.layout.activity_main);        DisplayMetrics displaymetrics =新DisplayMetrics();
        。getWindowManager()getDefaultDisplay()getMetrics(displaymetrics)。
        INT高度= displaymetrics.heightPixels;
        INT宽度= displaymetrics.widthPixels;
        //在主要布局图像视图由原始的位图组合填写
        ImageView的ImageView的=(ImageView的)findViewById(R.id.image);        //从文件中获取图像
        //从绘制文件夹中拍摄的RAW位图
        //位图底图= BitmapFactory.de codeResource(getResources(),R.drawable.arsenal);
        //位图topImage = BitmapFactory.de codeResource(getResources(),R.drawable.setare);        Log.v(ImageView的,将String.valueOf(imageView.getWidth())++ imageView.getHeight());        位图底图=去codeSampledBitmapFromResource(getResources()
                R.drawable.arsenal,宽度(INT)0.75 *宽);        位图topImage =去codeSampledBitmapFromResource(getResources()
                R.drawable.setare,400,400);        //以下位图是可变的副本。        位图TEMP = bottomImage.copy(Bitmap.Config.ARGB_8888,真); ///?!我得到的错误在这里!        //没有必要,只是为了测试是否是可能的diractly缓存文本视图或不
        TextView的T =(的TextView)findViewById(R.id.text);
        t.se​​tDrawingCacheEnabled(真);        //绘图画布功能
        帆布comboImage =新的Canvas(TEMP);
        //再画第二个最重要的是
        comboImage.drawBitmap(topImage,400F,400F,NULL);
        //油漆,以确定什么将在画布上绘制风格。
        涂料P =新的油漆();
        p.setColor(Color.YELLOW);
        p.setStyle(Style.FILL);
        p.setTextSize(70);        //手动绘制在画布上的文本
        comboImage.drawText(伊赫桑米尔扎拉齐,100,100,p)的;        //直接在画布上绘制文本视图。
        //现在会导致内存溢出异常
        //comboImage.drawBitmap(t.getDrawingCache(),1000F,200F,新的油漆());        //绘图画布编辑临时绘制,在ImageView的
        imageView.setImageDrawable(新BitmapDrawable(getResources(),温度));        //写入文件到SD卡中:
        OutputStream的OS = NULL;
        尝试{
            OS =新的FileOutputStream(myNewFileName.png);
            bottomImage.com preSS(比较pressFormat.PNG,100,OS);
            topImage.recycle();
            bottomImage.recycle();
            temp.recycle();
        }赶上(IOException异常五){
            e.printStackTrace();
        }    }
    @覆盖
    公共布尔onCreateOptionsMenu(菜单菜单){
        //充气菜单;如果是present这增加了项目操作栏。
        。getMenuInflater()膨胀(R.menu.activity_main,菜单);
        返回true;
    }    公共静态INT calculateInSampleSize(
            BitmapFactory.Options选项,诠释reqWidth,诠释reqHeight){
        //原始高度和图像宽度
        最终诠释身高= options.outHeight;
        最终诠释宽度= options.outWidth;
        INT inSampleSize = 1;        如果(高度> reqHeight ||宽度GT; reqWidth){            //计算的高度和宽度的比率要求的高度和宽度
            最终诠释heightRatio = Math.round((浮点)高度/(浮点)reqHeight);
            最终诠释widthRatio = Math.round((浮点)宽/(浮点)reqWidth);            //选择最小比率inSampleSize值,这将保证
            //使用两个维度大于或等于所述最终图像
            //请求的高度和宽度。
            inSampleSize = heightRatio< widthRatio? heightRatio:widthRatio;
        }
        Log.v(缩水,将String.valueOf(inSampleSize));
        返回inSampleSize;
    }    公共静态位图德codeSampledBitmapFromResource(资源RES,INT渣油,
            INT reqWidth,诠释reqHeight){        //首先去code。与inJustDe codeBounds = true来检查尺寸
        最后BitmapFactory.Options选项=新BitmapFactory.Options();
        options.inJustDe codeBounds = TRUE;
        BitmapFactory.de codeResource(RES,渣油,期权);        //计算inSampleSize
        options.inSampleSize = calculateInSampleSize(选项,reqWidth,reqHeight);        //德code位与inSampleSize集
        options.inJustDe codeBounds = FALSE;
        返回BitmapFactory.de codeResource(RES,渣油,期权);
    }    @覆盖
    保护无效的onDestroy(){
        // TODO自动生成方法存根
        super.onDestroy();        // ImageView的= NULL;    }
}


解决方案

这是发生,因为你正在创建的位图。每当你旋转设备,它会重新创建一个没有回收previous位图(因为的onCreate()时,会再次旋转设备拨打)。
所以用这个方法尝试 -

 公共类MainActivity延伸活动{
  位图底图,topImage,温度;
@覆盖
保护无效的onCreate(捆绑savedInstanceState){
    super.onCreate(savedInstanceState);
    的setContentView(R.layout.activity_main);    如果(底图!= NULL){
       bottomImage.recycle();
       底图= NULL;
     }
      如果(topImage!= NULL){
       topImage.recycle();
       topImage = NULL;
     }
     如果(温度!= NULL){
       temp.recycle();
       温度= NULL;
     }    DisplayMetrics displaymetrics =新DisplayMetrics();
    。getWindowManager()getDefaultDisplay()getMetrics(displaymetrics)。
    INT高度= displaymetrics.heightPixels;
    INT宽度= displaymetrics.widthPixels;
    //在主要布局图像视图由原始的位图组合填写
    ImageView的ImageView的=(ImageView的)findViewById(R.id.image);    //从文件中获取图像
    //从绘制文件夹中拍摄的RAW位图
    //位图底图= BitmapFactory.de codeResource(getResources(),R.drawable.arsenal);
    //位图topImage = BitmapFactory.de codeResource(getResources(),R.drawable.setare);    Log.v(ImageView的,将String.valueOf(imageView.getWidth())++ imageView.getHeight());    底图=去codeSampledBitmapFromResource(getResources()
            R.drawable.arsenal,宽度(INT)0.75 *宽);    topImage =去codeSampledBitmapFromResource(getResources()
            R.drawable.setare,400,400);    //以下位图是可变的副本。    TEMP = bottomImage.copy(Bitmap.Config.ARGB_8888,真); ///?!我得到的错误在这里!    //没有必要,只是为了测试是否是可能的diractly缓存文本视图或不
    TextView的T =(的TextView)findViewById(R.id.text);
    t.se​​tDrawingCacheEnabled(真);    //绘图画布功能
    帆布comboImage =新的Canvas(TEMP);
    //再画第二个最重要的是
    comboImage.drawBitmap(topImage,400F,400F,NULL);
    //油漆,以确定什么将在画布上绘制风格。
    涂料P =新的油漆();
    p.setColor(Color.YELLOW);
    p.setStyle(Style.FILL);
    p.setTextSize(70);    //手动绘制在画布上的文本
    comboImage.drawText(伊赫桑米尔扎拉齐,100,100,p)的;    //直接在画布上绘制文本视图。
    //现在会导致内存溢出异常
    //comboImage.drawBitmap(t.getDrawingCache(),1000F,200F,新的油漆());    //绘图画布编辑临时绘制,在ImageView的
    imageView.setImageDrawable(新BitmapDrawable(getResources(),温度));    //写入文件到SD卡中:
    OutputStream的OS = NULL;
    尝试{
        OS =新的FileOutputStream(myNewFileName.png);
        bottomImage.com preSS(比较pressFormat.PNG,100,OS);
        topImage.recycle();
        bottomImage.recycle();
        temp.recycle();
    }赶上(IOException异常五){
        e.printStackTrace();
    }}
@覆盖
公共布尔onCreateOptionsMenu(菜单菜单){
    //充气菜单;如果是present这增加了项目操作栏。
    。getMenuInflater()膨胀(R.menu.activity_main,菜单);
    返回true;
}公共静态INT calculateInSampleSize(
        BitmapFactory.Options选项,诠释reqWidth,诠释reqHeight){
    //原始高度和图像宽度
    最终诠释身高= options.outHeight;
    最终诠释宽度= options.outWidth;
    INT inSampleSize = 1;    如果(高度> reqHeight ||宽度GT; reqWidth){        //计算的高度和宽度的比率要求的高度和宽度
        最终诠释heightRatio = Math.round((浮点)高度/(浮点)reqHeight);
        最终诠释widthRatio = Math.round((浮点)宽/(浮点)reqWidth);        //选择最小比率inSampleSize值,这将保证
        //使用两个维度大于或等于所述最终图像
        //请求的高度和宽度。
        inSampleSize = heightRatio< widthRatio? heightRatio:widthRatio;
    }
    Log.v(缩水,将String.valueOf(inSampleSize));
    返回inSampleSize;
}公共静态位图德codeSampledBitmapFromResource(资源RES,INT渣油,
        INT reqWidth,诠释reqHeight){    //首先去code。与inJustDe codeBounds = true来检查尺寸
    最后BitmapFactory.Options选项=新BitmapFactory.Options();
    options.inJustDe codeBounds = TRUE;
    BitmapFactory.de codeResource(RES,渣油,期权);    //计算inSampleSize
    options.inSampleSize = calculateInSampleSize(选项,reqWidth,reqHeight);    //德code位与inSampleSize集
    options.inJustDe codeBounds = FALSE;
    返回BitmapFactory.de codeResource(RES,渣油,期权);
}@覆盖
保护无效的onDestroy(){
    // TODO自动生成方法存根
    super.onDestroy();    // ImageView的= NULL;}
}

<一个href=\"http://stackoverflow.com/questions/17744828/bitmap-and-outofmemory-in-android/17745049#17745049\">see这也

I have a very simple Activity that draws a drawable on another drawable in a Canvas and in the end shows it on a ImageView. I know that creating bitmaps takes too much memory and scale them down and I know about leaking by keeping reference to context, but can not detect where it happens. by now after 4-5 times rotating I get out of memory error. (I've specified that on code)

Can you help me find where leak happens?

here is my code:

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        DisplayMetrics displaymetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
        int height = displaymetrics.heightPixels;
        int width = displaymetrics.widthPixels;


        // image view in main layout to be filled by raw bitmaps combination
        ImageView imageView = (ImageView) findViewById(R.id.image);

        // Get your images from their files
        // raw bitmaps taken from drawable folder
        //Bitmap bottomImage = BitmapFactory.decodeResource(getResources(), R.drawable.arsenal);
        //Bitmap topImage = BitmapFactory.decodeResource(getResources(), R.drawable.setare);

        Log.v("imageView", String.valueOf(imageView.getWidth()) + " " + imageView.getHeight());

        Bitmap bottomImage = decodeSampledBitmapFromResource(getResources(),
                R.drawable.arsenal, width, (int)0.75 * width);

        Bitmap topImage = decodeSampledBitmapFromResource(getResources(),
                R.drawable.setare, 400, 400);

        // a copy of the below bitmap that is mutable.

        Bitmap temp = bottomImage.copy(Bitmap.Config.ARGB_8888, true); /// ?! I get error here! 

        // not necessary, only for testing whether is possible to diractly cache a text view or not
        TextView t = (TextView) findViewById(R.id.text);
        t.setDrawingCacheEnabled(true);

        // canvas for drawing functions
        Canvas comboImage = new Canvas(temp);
        // Then draw the second on top of that
        comboImage.drawBitmap(topImage, 400f, 400f, null);


        // a paint to determine style of what would be drawn in canvas.
        Paint p = new Paint();
        p.setColor(Color.YELLOW);
        p.setStyle(Style.FILL);
        p.setTextSize(70);

        // manually draw a text on canvas
        comboImage.drawText("Ehsan Mirza Razi", 100, 100, p);

        // draw text view directly on canvas. 
        //by now causes out of memory exception 
        //comboImage.drawBitmap(t.getDrawingCache(), 1000f, 200f, new Paint());

        // drawing the temp drawable edited in canvas, on ImageView
        imageView.setImageDrawable(new BitmapDrawable(getResources(), temp));

        // To write the file out to the SDCard:
        OutputStream os = null;
        try {
            os = new FileOutputStream("myNewFileName.png");
            bottomImage.compress(CompressFormat.PNG, 100, os);
            topImage.recycle();
            bottomImage.recycle();
            temp.recycle();
        } catch(IOException e) {
            e.printStackTrace();
        }

    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

    public static int calculateInSampleSize(
            BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {

            // Calculate ratios of height and width to requested height and width
            final int heightRatio = Math.round((float) height / (float) reqHeight);
            final int widthRatio = Math.round((float) width / (float) reqWidth);

            // Choose the smallest ratio as inSampleSize value, this will guarantee
            // a final image with both dimensions larger than or equal to the
            // requested height and width.
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        }
        Log.v("shrink", String.valueOf(inSampleSize));
        return inSampleSize;
    }

    public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
            int reqWidth, int reqHeight) {

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();

        //ImageView = null;

    }
}

解决方案

That is happening because You are creating Bitmaps. And whenever You rotate device it will again create without recycling previous bitmaps(Because onCreate() again call when you rotate device). So try with this way-

 public class MainActivity extends Activity {
  Bitmap bottomImage,topImage,temp;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if(bottomImage!=null){
       bottomImage.recycle();
       bottomImage=null;
     }
      if(topImage!=null){
       topImage.recycle();
       topImage=null;
     }
     if(temp!=null){
       temp.recycle();
       temp=null;
     }

    DisplayMetrics displaymetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
    int height = displaymetrics.heightPixels;
    int width = displaymetrics.widthPixels;


    // image view in main layout to be filled by raw bitmaps combination
    ImageView imageView = (ImageView) findViewById(R.id.image);

    // Get your images from their files
    // raw bitmaps taken from drawable folder
    //Bitmap bottomImage = BitmapFactory.decodeResource(getResources(), R.drawable.arsenal);
    //Bitmap topImage = BitmapFactory.decodeResource(getResources(), R.drawable.setare);

    Log.v("imageView", String.valueOf(imageView.getWidth()) + " " + imageView.getHeight());

    bottomImage = decodeSampledBitmapFromResource(getResources(),
            R.drawable.arsenal, width, (int)0.75 * width);

    topImage = decodeSampledBitmapFromResource(getResources(),
            R.drawable.setare, 400, 400);

    // a copy of the below bitmap that is mutable.

    temp = bottomImage.copy(Bitmap.Config.ARGB_8888, true); /// ?! I get error here! 

    // not necessary, only for testing whether is possible to diractly cache a text view or not
    TextView t = (TextView) findViewById(R.id.text);
    t.setDrawingCacheEnabled(true);

    // canvas for drawing functions
    Canvas comboImage = new Canvas(temp);
    // Then draw the second on top of that
    comboImage.drawBitmap(topImage, 400f, 400f, null);


    // a paint to determine style of what would be drawn in canvas.
    Paint p = new Paint();
    p.setColor(Color.YELLOW);
    p.setStyle(Style.FILL);
    p.setTextSize(70);

    // manually draw a text on canvas
    comboImage.drawText("Ehsan Mirza Razi", 100, 100, p);

    // draw text view directly on canvas. 
    //by now causes out of memory exception 
    //comboImage.drawBitmap(t.getDrawingCache(), 1000f, 200f, new Paint());

    // drawing the temp drawable edited in canvas, on ImageView
    imageView.setImageDrawable(new BitmapDrawable(getResources(), temp));

    // To write the file out to the SDCard:
    OutputStream os = null;
    try {
        os = new FileOutputStream("myNewFileName.png");
        bottomImage.compress(CompressFormat.PNG, 100, os);
        topImage.recycle();
        bottomImage.recycle();
        temp.recycle();
    } catch(IOException e) {
        e.printStackTrace();
    }

}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.activity_main, menu);
    return true;
}

public static int calculateInSampleSize(
        BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        // Choose the smallest ratio as inSampleSize value, this will guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }
    Log.v("shrink", String.valueOf(inSampleSize));
    return inSampleSize;
}

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
        int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

@Override
protected void onDestroy() {
    // TODO Auto-generated method stub
    super.onDestroy();

    //ImageView = null;

}
}

see this also

这篇关于旋转手机会导致内存的内存不足的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆