使用后置摄像头时发生致命异常 java.lang.outofmemory
fatal exception java.lang.outofmemory when using back camera
我制作了一个 android 应用程序来捕获图像并在图像上添加标题。当我从手机摄像头使用时应用程序正常工作,但是当我使用后置摄像头时应用程序崩溃并出现错误 java.lang.outofmemory
我的代码在这里
public class MainActivity extends AppCompatActivity {
private ImageView imageResult;
Bitmap processedBitmap;
String photoName;
Uri source1;
private String pictureImagePath = "";
File imgFile;
/**
* ATTENTION: This was auto-generated to implement the App Indexing API.
* See https://g.co/AppIndexing/AndroidStudio for more information.
*/
private GoogleApiClient client;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageResult = (ImageView) this.findViewById(R.id.imageView1);
Button takePicture = (Button) this.findViewById(R.id.btnTakePic);
Button renamePicture = (Button) this.findViewById(R.id.btnRename);
Button savePicture = (Button) this.findViewById(R.id.btnSave);
final File myDir=new File("/sdcard/saved_images");
myDir.mkdirs();
File myDirTemp = new File("/sdcard/saved_images/Temp");
myDirTemp.mkdirs();
takePicture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = timeStamp + ".jpg";
File storageDir = new File("/sdcard/saved_images/Temp");
pictureImagePath = storageDir.getAbsolutePath() + "/" + imageFileName;
File file = new File(pictureImagePath);
Uri outputFileUri = Uri.fromFile(file);
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
startActivityForResult(cameraIntent, 1);
}
});
renamePicture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(source1!=null){
AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this);
final EditText input = new EditText(MainActivity.this);
input.setInputType(InputType.TYPE_CLASS_NUMBER);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
input.setLayoutParams(lp);
dialog.setView(input);
dialog.setCancelable(false);
dialog.setTitle("Rename Photo");
dialog.setMessage("Enter Photo Name");
dialog.setPositiveButton("Save", null);
dialog.setNegativeButton("cancel", null);
final AlertDialog alertdialog = dialog.create();
alertdialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
// TODO Auto-generated method stub
Button b = alertdialog.getButton(AlertDialog.BUTTON_POSITIVE);
Button c = alertdialog.getButton(AlertDialog.BUTTON_NEGATIVE);
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
String SpinName = input.getText().toString();
if(SpinName.length()==0){
Toast.makeText(MainActivity.this, "Enter Photo Name", Toast.LENGTH_LONG).show();
}else{
photoName = input.getText().toString();
processedBitmap = ProcessingBitmap();
if(processedBitmap != null){
imageResult.setImageBitmap(processedBitmap);
}
}
alertdialog.dismiss();
}
});
c.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
alertdialog.dismiss();
}
});
}
});alertdialog.show();}
else{
Toast.makeText(MainActivity.this, "Take Image First", Toast.LENGTH_LONG).show();
}
}
});
savePicture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(source1!=null){
String fname = photoName +".jpg";
File file = new File (myDir, fname);
if (file.exists ()) file.delete ();
try {
FileOutputStream out = new FileOutputStream(file);
processedBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
AlertDialog.Builder aldialog = (new AlertDialog.Builder(MainActivity.this));
aldialog.setTitle("saved");
aldialog.setMessage("Image Saved Successfully");
aldialog.setPositiveButton("OK", new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
imageResult.setImageResource(0);
source1 = null;
}
});aldialog.show();
} catch (Exception e) {
e.printStackTrace();
}
}
else{
Toast.makeText(MainActivity.this, "Take Image First", Toast.LENGTH_LONG).show();
}
}
});
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 1) {
imgFile = new File(pictureImagePath);
if(imgFile.exists()){
source1 = Uri.fromFile(imgFile);
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
imageResult.setImageBitmap(myBitmap);
}
}
}
private Bitmap ProcessingBitmap() {
Bitmap bm1 = null;
Bitmap newBitmap = null;
try{
bm1 = BitmapFactory.decodeStream(getContentResolver().openInputStream(Uri.fromFile(imgFile)));
Bitmap.Config config = bm1.getConfig();
if(config==null){
config = Bitmap.Config.ARGB_8888;
}
newBitmap = Bitmap.createBitmap(bm1.getWidth(), bm1.getHeight(),config);
Canvas newCanvas = new Canvas(newBitmap);
newCanvas.drawBitmap(bm1,0,0,null);
if(photoName!= null){
Paint paintText = new Paint(Paint.ANTI_ALIAS_FLAG);
paintText.setColor(Color.WHITE);
paintText.setTextSize(120);
paintText.setShadowLayer(10f,10f,10f, Color.BLACK);
Rect rectText = new Rect();
paintText.getTextBounds(photoName, 0, photoName.length(), rectText);
newCanvas.drawText(photoName, 0, bm1.getHeight()- rectText.height(), paintText);
//newCanvas.drawText(photoName,bm1.getWidth()-rectText.left,bm1.getWidth()-rectText.top, paintText);
Toast.makeText(MainActivity.this, "done", Toast.LENGTH_LONG).show();}
else{
Toast.makeText(MainActivity.this, "undone", Toast.LENGTH_LONG).show();}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return newBitmap;
}
}
请说出一些建议。
异常日志在这里
E/AndroidRuntime:致命异常:main
进程:com.surveyphotoapp,PID:24765
java.lang.OutOfMemoryError
在 android.graphics.Bitmap.nativeCreate(本机方法)
在 android.graphics.Bitmap.createBitmap(Bitmap.java:822)
在 android.graphics.Bitmap.createBitmap(Bitmap.java:799)
在 android.graphics.Bitmap.createBitmap(Bitmap.java:766)
在 com.surveyphotoapp.MainActivity.ProcessingBitmap(MainActivity.java:214)
在 com.surveyphotoapp.MainActivity.access$100(MainActivity.java:44)
在 com.surveyphotoapp.MainActivity$2$1$1.onClick(MainActivity.java:127)
在 android.view.View.performClick(View.java:4444)
在 android.view.View$PerformClick.run(View.java:18440)
在 android.os.Handler.handleCallback(Handler.java:733)
在 android.os.Handler.dispatchMessage(Handler.java:95)
在 android.os.Looper.loop(Looper.java:136)
在 android.app.ActivityThread.main(ActivityThread.java:5052)
在 java.lang.reflect.Method.invokeNative(本机方法)
在 java.lang.reflect.Method.invoke(Method.java:515)
在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:796)
在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:612)
在 dalvik.system.NativeStart.main(本机方法)
后置摄像头的图像分辨率高于前置摄像头。因此,从字节流直接创建位图可能会因 OutOfMemoryError 而失败,尤其是在 VM 堆大小较小的设备上。
为避免小 VM 堆大小的错误,您可以在解码位图时捕获 OutOfMemoryError,如果发生这种情况,请减小图像大小并重试。
public static Bitmap getBitmapFromStream(Context context, InputStream istr) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
final int REQUIRED_SIZE = display.getWidth();
istr.mark(Integer.MAX_VALUE);
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(istr, null, o);
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true){
if (width_tmp / 2 < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
while (true) {
try {
istr.reset();
o = new BitmapFactory.Options();
o.inSampleSize = scale;
return BitmapFactory.decodeStream(istr, null, o);
} catch (OutOfMemoryError ex) {
scale *= 2;
if (scale >= 32) {
// Failed
return null;
}
} catch (IOException ex) {
ex.printStackTrace();
return null;
}
}
}
我制作了一个 android 应用程序来捕获图像并在图像上添加标题。当我从手机摄像头使用时应用程序正常工作,但是当我使用后置摄像头时应用程序崩溃并出现错误 java.lang.outofmemory 我的代码在这里
public class MainActivity extends AppCompatActivity {
private ImageView imageResult;
Bitmap processedBitmap;
String photoName;
Uri source1;
private String pictureImagePath = "";
File imgFile;
/**
* ATTENTION: This was auto-generated to implement the App Indexing API.
* See https://g.co/AppIndexing/AndroidStudio for more information.
*/
private GoogleApiClient client;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageResult = (ImageView) this.findViewById(R.id.imageView1);
Button takePicture = (Button) this.findViewById(R.id.btnTakePic);
Button renamePicture = (Button) this.findViewById(R.id.btnRename);
Button savePicture = (Button) this.findViewById(R.id.btnSave);
final File myDir=new File("/sdcard/saved_images");
myDir.mkdirs();
File myDirTemp = new File("/sdcard/saved_images/Temp");
myDirTemp.mkdirs();
takePicture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = timeStamp + ".jpg";
File storageDir = new File("/sdcard/saved_images/Temp");
pictureImagePath = storageDir.getAbsolutePath() + "/" + imageFileName;
File file = new File(pictureImagePath);
Uri outputFileUri = Uri.fromFile(file);
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
startActivityForResult(cameraIntent, 1);
}
});
renamePicture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(source1!=null){
AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this);
final EditText input = new EditText(MainActivity.this);
input.setInputType(InputType.TYPE_CLASS_NUMBER);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
input.setLayoutParams(lp);
dialog.setView(input);
dialog.setCancelable(false);
dialog.setTitle("Rename Photo");
dialog.setMessage("Enter Photo Name");
dialog.setPositiveButton("Save", null);
dialog.setNegativeButton("cancel", null);
final AlertDialog alertdialog = dialog.create();
alertdialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
// TODO Auto-generated method stub
Button b = alertdialog.getButton(AlertDialog.BUTTON_POSITIVE);
Button c = alertdialog.getButton(AlertDialog.BUTTON_NEGATIVE);
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
String SpinName = input.getText().toString();
if(SpinName.length()==0){
Toast.makeText(MainActivity.this, "Enter Photo Name", Toast.LENGTH_LONG).show();
}else{
photoName = input.getText().toString();
processedBitmap = ProcessingBitmap();
if(processedBitmap != null){
imageResult.setImageBitmap(processedBitmap);
}
}
alertdialog.dismiss();
}
});
c.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
alertdialog.dismiss();
}
});
}
});alertdialog.show();}
else{
Toast.makeText(MainActivity.this, "Take Image First", Toast.LENGTH_LONG).show();
}
}
});
savePicture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(source1!=null){
String fname = photoName +".jpg";
File file = new File (myDir, fname);
if (file.exists ()) file.delete ();
try {
FileOutputStream out = new FileOutputStream(file);
processedBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
AlertDialog.Builder aldialog = (new AlertDialog.Builder(MainActivity.this));
aldialog.setTitle("saved");
aldialog.setMessage("Image Saved Successfully");
aldialog.setPositiveButton("OK", new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
imageResult.setImageResource(0);
source1 = null;
}
});aldialog.show();
} catch (Exception e) {
e.printStackTrace();
}
}
else{
Toast.makeText(MainActivity.this, "Take Image First", Toast.LENGTH_LONG).show();
}
}
});
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 1) {
imgFile = new File(pictureImagePath);
if(imgFile.exists()){
source1 = Uri.fromFile(imgFile);
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
imageResult.setImageBitmap(myBitmap);
}
}
}
private Bitmap ProcessingBitmap() {
Bitmap bm1 = null;
Bitmap newBitmap = null;
try{
bm1 = BitmapFactory.decodeStream(getContentResolver().openInputStream(Uri.fromFile(imgFile)));
Bitmap.Config config = bm1.getConfig();
if(config==null){
config = Bitmap.Config.ARGB_8888;
}
newBitmap = Bitmap.createBitmap(bm1.getWidth(), bm1.getHeight(),config);
Canvas newCanvas = new Canvas(newBitmap);
newCanvas.drawBitmap(bm1,0,0,null);
if(photoName!= null){
Paint paintText = new Paint(Paint.ANTI_ALIAS_FLAG);
paintText.setColor(Color.WHITE);
paintText.setTextSize(120);
paintText.setShadowLayer(10f,10f,10f, Color.BLACK);
Rect rectText = new Rect();
paintText.getTextBounds(photoName, 0, photoName.length(), rectText);
newCanvas.drawText(photoName, 0, bm1.getHeight()- rectText.height(), paintText);
//newCanvas.drawText(photoName,bm1.getWidth()-rectText.left,bm1.getWidth()-rectText.top, paintText);
Toast.makeText(MainActivity.this, "done", Toast.LENGTH_LONG).show();}
else{
Toast.makeText(MainActivity.this, "undone", Toast.LENGTH_LONG).show();}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return newBitmap;
}
}
请说出一些建议。 异常日志在这里
E/AndroidRuntime:致命异常:main 进程:com.surveyphotoapp,PID:24765 java.lang.OutOfMemoryError 在 android.graphics.Bitmap.nativeCreate(本机方法) 在 android.graphics.Bitmap.createBitmap(Bitmap.java:822) 在 android.graphics.Bitmap.createBitmap(Bitmap.java:799) 在 android.graphics.Bitmap.createBitmap(Bitmap.java:766) 在 com.surveyphotoapp.MainActivity.ProcessingBitmap(MainActivity.java:214) 在 com.surveyphotoapp.MainActivity.access$100(MainActivity.java:44) 在 com.surveyphotoapp.MainActivity$2$1$1.onClick(MainActivity.java:127) 在 android.view.View.performClick(View.java:4444) 在 android.view.View$PerformClick.run(View.java:18440) 在 android.os.Handler.handleCallback(Handler.java:733) 在 android.os.Handler.dispatchMessage(Handler.java:95) 在 android.os.Looper.loop(Looper.java:136) 在 android.app.ActivityThread.main(ActivityThread.java:5052) 在 java.lang.reflect.Method.invokeNative(本机方法) 在 java.lang.reflect.Method.invoke(Method.java:515) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:796) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:612) 在 dalvik.system.NativeStart.main(本机方法)
后置摄像头的图像分辨率高于前置摄像头。因此,从字节流直接创建位图可能会因 OutOfMemoryError 而失败,尤其是在 VM 堆大小较小的设备上。
为避免小 VM 堆大小的错误,您可以在解码位图时捕获 OutOfMemoryError,如果发生这种情况,请减小图像大小并重试。
public static Bitmap getBitmapFromStream(Context context, InputStream istr) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
final int REQUIRED_SIZE = display.getWidth();
istr.mark(Integer.MAX_VALUE);
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(istr, null, o);
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true){
if (width_tmp / 2 < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
while (true) {
try {
istr.reset();
o = new BitmapFactory.Options();
o.inSampleSize = scale;
return BitmapFactory.decodeStream(istr, null, o);
} catch (OutOfMemoryError ex) {
scale *= 2;
if (scale >= 32) {
// Failed
return null;
}
} catch (IOException ex) {
ex.printStackTrace();
return null;
}
}
}