我有一个非常简单的Activity
,它在Canvas
中的另一个drawable上绘制了一个drawable,最后在ImageView
上显示了它。我知道创建位图需要占用太多内存并将其缩小,我知道通过保持对上下文的引用来泄漏,但无法检测它发生的位置。到现在,经过4-5次旋转,我的内存出错了。 (我已经在代码中指定了)
你能帮我找一下泄漏的地方吗?
这是我的代码:
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;
}
}
答案 0 :(得分:1)
在每次旋转(纵向 - &gt;横向,反之亦然)时,将重新创建活动,并且某些设备在“原始”模式下没有足够的内存用于转换。您应该检查以下链接,因为它解释了如何以一种很好的方式处理它。 (IMHO)
答案 1 :(得分:1)
这种情况正在发生,因为您正在创建位图。每当您旋转设备时,它将再次创建而不回收以前的位图(因为onCreate()在您旋转设备时再次调用)。 所以试试这种方式 -
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;
}
}