我尝试在用户点击时多次旋转位图。我的rotateBitmap函数总是返回一个新的Bitmap,我保存在内存Bitmap中。为了能够回收位图,我有两个不同的Bitmap变量,我将Bitmap存储在一个而我循环使用其他变量。
尽管如此,我在一些轮换后得到一个OutOfMemorError(位图大小超过VM预算)。我做错了什么?为什么回收不起作用?
这是我的代码:
private Bitmap myBitmap, myBitmap2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("", "Estamos en oncreate");
setContentView(R.layout.activity_rotate);
// Show the Up button in the action bar.
super.setUpActionBar(getResources().getString(
R.string.title_activity_detalle_producto));
image = (ImageView) findViewById(R.id.rotate_image);
imageURI = getIntent().getStringExtra(SELECTEDIMAGEURI);
rotatedImageURI = getIntent().getStringExtra(ROTATEDIMAGEURI);
File imgFile = new File(imageURI);
if (imgFile.exists()) {
myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
image.setImageBitmap(myBitmap);
}
}
public void rotateLeft(View v) {
if(myBitmap!=null){
myBitmap2 = rotateBitmap(myBitmap, -90);
image.setImageBitmap(myBitmap2);
myBitmap.recycle();
myBitmap = null;
}else {
myBitmap = rotateBitmap(myBitmap2, -90);
image.setImageBitmap(myBitmap);
myBitmap2.recycle();
myBitmap2=null;
}
}
public void rotateRight(View v) {
if(myBitmap!=null){
myBitmap2 = rotateBitmap(myBitmap, 90);
image.setImageBitmap(myBitmap2);
myBitmap.recycle();
myBitmap = null;
}else {
myBitmap = rotateBitmap(myBitmap2, 90);
image.setImageBitmap(myBitmap);
myBitmap2.recycle();
myBitmap2=null;
}
}
public void done(View v) {
saveToSD(myBitmap, rotatedImageURI);
// finish();
}
public static Bitmap rotateBitmap(Bitmap source, int angle) {
Matrix matrix = new Matrix();
matrix.postRotate(angle);
return Bitmap.createBitmap(source, 0, 0, source.getWidth(),
source.getHeight(), matrix, true);
}
这是我的堆栈跟踪:
06-12 08:57:03.620: E/AndroidRuntime(20121): FATAL EXCEPTION: main
06-12 08:57:03.620: E/AndroidRuntime(20121): java.lang.IllegalStateException: Could not execute method of the activity
06-12 08:57:03.620: E/AndroidRuntime(20121): at android.view.View$1.onClick(View.java:2154)
06-12 08:57:03.620: E/AndroidRuntime(20121): at android.view.View.performClick(View.java:2538)
06-12 08:57:03.620: E/AndroidRuntime(20121): at android.view.View$PerformClick.run(View.java:9152)
06-12 08:57:03.620: E/AndroidRuntime(20121): at android.os.Handler.handleCallback(Handler.java:587)
06-12 08:57:03.620: E/AndroidRuntime(20121): at android.os.Handler.dispatchMessage(Handler.java:92)
06-12 08:57:03.620: E/AndroidRuntime(20121): at android.os.Looper.loop(Looper.java:130)
06-12 08:57:03.620: E/AndroidRuntime(20121): at android.app.ActivityThread.main(ActivityThread.java:3691)
06-12 08:57:03.620: E/AndroidRuntime(20121): at java.lang.reflect.Method.invokeNative(Native Method)
06-12 08:57:03.620: E/AndroidRuntime(20121): at java.lang.reflect.Method.invoke(Method.java:507)
06-12 08:57:03.620: E/AndroidRuntime(20121): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:907)
06-12 08:57:03.620: E/AndroidRuntime(20121): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:665)
06-12 08:57:03.620: E/AndroidRuntime(20121): at dalvik.system.NativeStart.main(Native Method)
06-12 08:57:03.620: E/AndroidRuntime(20121): Caused by: java.lang.reflect.InvocationTargetException
06-12 08:57:03.620: E/AndroidRuntime(20121): at java.lang.reflect.Method.invokeNative(Native Method)
06-12 08:57:03.620: E/AndroidRuntime(20121): at java.lang.reflect.Method.invoke(Method.java:507)
06-12 08:57:03.620: E/AndroidRuntime(20121): at android.view.View$1.onClick(View.java:2149)
06-12 08:57:03.620: E/AndroidRuntime(20121): ... 11 more
06-12 08:57:03.620: E/AndroidRuntime(20121): Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
06-12 08:57:03.620: E/AndroidRuntime(20121): at android.graphics.Bitmap.nativeCreate(Native Method)
06-12 08:57:03.620: E/AndroidRuntime(20121): at android.graphics.Bitmap.createBitmap(Bitmap.java:477)
06-12 08:57:03.620: E/AndroidRuntime(20121): at android.graphics.Bitmap.createBitmap(Bitmap.java:444)
06-12 08:57:03.620: E/AndroidRuntime(20121): at com.zonaapp.imoments.RotateActivity.rotateBitmap(RotateActivity.java:93)
06-12 08:57:03.620: E/AndroidRuntime(20121): at com.zonaapp.imoments.RotateActivity.rotateRight(RotateActivity.java:77)
06-12 08:57:03.620: E/AndroidRuntime(20121): ... 14 more
06-12 08:57:03.625: E/(2704): Dumpstate > /data/log/dumpstate_app_error
答案 0 :(得分:0)
这里似乎有两个目标。 1)每次用户点击图像时显示旋转的图像,2)将完全旋转的位图保存到磁盘,以便稍后发送到打印机。目前,您正在尝试同时完成这两项任务,但这可能不是最好的方法。使用内置的动画类的一个很好的理由(可能是你获得OOM的原因)是每当你调用Bitmap.recycle()时,它只是对垃圾收集器的一个建议,但它仍然由GC来决定绕过来释放那段记忆。如果你在一起进行多次旋转,你很容易得到OOM。如果这是正确的,那么你点击的速度越快,获得OOM的可能性越大,你点击的速度越慢,获得OOM的可能性就越小。
您应该考虑使用Androids built in Animation classes(例如Value Animator)为ImageView的旋转值设置动画。如果您想确保向后兼容动画,最好使用NineOldAndroids。
您不需要,也不希望在内存中保留此位图的两个版本。此外,如果位图不必要地大,您可以将其缩小到适当的大小。在Android中使用位图的一个很好的参考是https://developer.android.com/training/displaying-bitmaps/index.html