安卓:激活相机后出现异常



我正在为安卓开发简单的绘图应用程序。我的目标是:

  1. 从我的应用程序中打开相机
  2. 拍照
  3. 将此照片绘制到画布中
  4. 在这张照片上画画

激活相机后:

Intent takePhoto = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePhoto.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takePhoto, CAMERA_INTENT_CALLED);
}

当我尝试将照片绘制到画布中时:

else if (requestCode == CAMERA_INTENT_CALLED) {
if (resultCode == RESULT_OK) {
Bundle extras = returnedIntent.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
drawView.drawImage(imageBitmap);
}
}

我得到空指针异常:尝试调用虚拟方法说我的画布为空。将照片从图库加载到画布中工作正常。可能是我的活动在激活相机后被破坏,所以我做了一个包装器来使我的画布可序列化:

public class SerializableCanvas extends Canvas implements Serializable {
public SerializableCanvas(Bitmap canvasBitmap) {
super(canvasBitmap);
}
}

并试图保存我的画布:

protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("drawCanvas", drawView.getDrawCanvas());
}

并恢复它:

protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (savedInstanceState != null) {
if (savedInstanceState.containsKey("drawCanvas")) {
drawView.setDrawCanvas((SerializableCanvas)savedInstanceState.getSerializable("drawCanvas"));
}
}
}

但是现在我收到一个错误,说此片段中的宽度和高度必须为>0:

public void drawImage(Bitmap image) {
drawCanvas.drawBitmap(resize(image, drawCanvas.getWidth(), drawCanvas.getHeight()), 0, 0, canvasPaint);
invalidate();
}

我也尝试保存整个 DrawingView 对象,但它太大并且里面有一个位图。 我有2个类:MainActivity和DrawingView。如果 sameone 知道如何克服这个问题,我将不胜感激。完整代码如下。

主活动类:

public class MainActivity extends Activity implements View.OnClickListener {
private DrawingView drawView;
private ImageButton currPaint;
private ImageButton drawBtn;
private ImageButton eraseBtn;
private ImageButton newBtn;
private ImageButton saveBtn;
private ImageButton openBtn;
private ImageButton cameraBtn;
private float smallBrush;
private float mediumBrush;
private float largeBrush;
private Drawable image;
private final int GALLERY_INTENT_CALLED = 1;
private final int CAMERA_INTENT_CALLED = 2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
drawView = (DrawingView)findViewById(R.id.drawing);
LinearLayout paintLayout = (LinearLayout)findViewById(R.id.paint_colors);
currPaint = (ImageButton)paintLayout.getChildAt(0);
currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed));
smallBrush = getResources().getInteger(R.integer.small_size);
mediumBrush = getResources().getInteger(R.integer.medium_size);
largeBrush = getResources().getInteger(R.integer.large_size);
drawBtn = (ImageButton)findViewById(R.id.draw_btn);
drawBtn.setOnClickListener(this);
eraseBtn = (ImageButton)findViewById(R.id.erase_btn);
eraseBtn.setOnClickListener(this);
newBtn = (ImageButton)findViewById(R.id.new_btn);
newBtn.setOnClickListener(this);
saveBtn = (ImageButton)findViewById(R.id.save_btn);
saveBtn.setOnClickListener(this);
openBtn = (ImageButton)findViewById(R.id.open_btn);
openBtn.setOnClickListener(this);
cameraBtn = (ImageButton)findViewById(R.id.camera_btn);
cameraBtn.setOnClickListener(this);
drawView.setBrushSize(mediumBrush);
}
public void paintClicked(View view){
drawView.setErase(false);
drawView.setBrushSize(drawView.getLastBrushSize());
if(view!=currPaint){
ImageButton imgView = (ImageButton)view;
String color = view.getTag().toString();
drawView.setColor(color);
imgView.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed));
currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint));
currPaint=(ImageButton)view;
}
}
@Override
public void onClick(View view) {
if(view.getId()==R.id.draw_btn){
proceedDrawButtonAction();
}else if(view.getId()==R.id.erase_btn){
proceedEraseButtonAction();
}else if(view.getId()==R.id.new_btn){
proceedNewButtonAction();
}else if(view.getId()==R.id.save_btn){
proceedSaveButtonAction();
}else if(view.getId()==R.id.open_btn){
proceedOpenButtonAction();
}else if(view.getId()==R.id.camera_btn){
proceedCameraButtonAction();
}
}
public void proceedDrawButtonAction(){
final Dialog brushDialog = new Dialog(this);
brushDialog.setTitle("Brush size:");
brushDialog.setContentView(R.layout.brush_chooser);
brushDialog.show();
ImageButton smallBtn = (ImageButton)brushDialog.findViewById(R.id.small_brush);
smallBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
drawView.setErase(false);
drawView.setBrushSize(smallBrush);
drawView.setLastBrushSize(smallBrush);
brushDialog.dismiss();
}
});
ImageButton mediumBtn = (ImageButton)brushDialog.findViewById(R.id.medium_brush);
mediumBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
drawView.setErase(false);
drawView.setBrushSize(mediumBrush);
drawView.setLastBrushSize(mediumBrush);
brushDialog.dismiss();
}
});
ImageButton largeBtn = (ImageButton)brushDialog.findViewById(R.id.large_brush);
largeBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
drawView.setErase(false);
drawView.setBrushSize(largeBrush);
drawView.setLastBrushSize(largeBrush);
brushDialog.dismiss();
}
});
}
public void proceedEraseButtonAction(){
final Dialog brushDialog = new Dialog(this);
brushDialog.setTitle("Eraser size:");
brushDialog.setContentView(R.layout.brush_chooser);
brushDialog.show();
ImageButton smallBtn = (ImageButton)brushDialog.findViewById(R.id.small_brush);
smallBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
drawView.setErase(true);
drawView.setBrushSize(smallBrush);
brushDialog.dismiss();
}
});
ImageButton mediumBtn = (ImageButton)brushDialog.findViewById(R.id.medium_brush);
mediumBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
drawView.setErase(true);
drawView.setBrushSize(mediumBrush);
brushDialog.dismiss();
}
});
ImageButton largeBtn = (ImageButton)brushDialog.findViewById(R.id.large_brush);
largeBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
drawView.setErase(true);
drawView.setBrushSize(largeBrush);
brushDialog.dismiss();
}
});
}
public void proceedNewButtonAction(){
AlertDialog.Builder yesNoDialog = new AlertDialog.Builder(this);
yesNoDialog.setTitle("New drawing");
yesNoDialog.setMessage("Start new drawing (you will lose the current drawing)?");
yesNoDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which){
drawView.startNew();
dialog.dismiss();
}
});
yesNoDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which){
dialog.cancel();
}
});
yesNoDialog.show();
}
public void proceedSaveButtonAction(){
AlertDialog.Builder saveDialog = new AlertDialog.Builder(this);
saveDialog.setTitle("Save drawing");
saveDialog.setMessage("Save drawing to device Gallery?");
saveDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which){
drawView.setDrawingCacheEnabled(true);
String imgSaved = MediaStore.Images.Media.insertImage(
getContentResolver(), drawView.getDrawingCache(),
UUID.randomUUID().toString()+".png", "drawing");
if(imgSaved!=null){
Toast savedToast = Toast.makeText(getApplicationContext(),
"Drawing saved to Gallery!", Toast.LENGTH_SHORT);
savedToast.show();
}
else{
Toast unsavedToast = Toast.makeText(getApplicationContext(),
"Image could not be saved.", Toast.LENGTH_SHORT);
unsavedToast.show();
}
drawView.destroyDrawingCache();
}
});
saveDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which){
dialog.cancel();
}
});
saveDialog.show();
}
public void proceedOpenButtonAction(){
AlertDialog.Builder yesNoDialog = new AlertDialog.Builder(this);
yesNoDialog.setTitle("Load image");
yesNoDialog.setMessage("Load image from gallery (you will lose the current drawing)?");
yesNoDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which){
Intent pickPhoto = new Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(pickPhoto, GALLERY_INTENT_CALLED);
}
});
yesNoDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which){
dialog.cancel();
}
});
yesNoDialog.show();
}
public void proceedCameraButtonAction(){
AlertDialog.Builder yesNoDialog = new AlertDialog.Builder(this);
yesNoDialog.setTitle("Take a photo");
yesNoDialog.setMessage("Take a photo and start drawing (you will lose the current drawing)?");
yesNoDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which){
Intent takePhoto = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePhoto.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takePhoto, CAMERA_INTENT_CALLED);
}
}
});
yesNoDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which){
dialog.cancel();
}
});
yesNoDialog.show();
}
protected void onActivityResult(int requestCode, int resultCode, Intent returnedIntent) {
super.onActivityResult(requestCode, resultCode, returnedIntent);
if (requestCode == GALLERY_INTENT_CALLED) {
if (resultCode == RESULT_OK) {
try {
Uri selectedImage = returnedIntent.getData();
InputStream inputStream = getContentResolver().openInputStream(selectedImage);
image = Drawable.createFromStream(inputStream, selectedImage.toString());
} catch (FileNotFoundException e) {}
drawView.drawImage(drawableToBitmap(image));
}
}else if (requestCode == CAMERA_INTENT_CALLED) {
if (resultCode == RESULT_OK) {
Bundle extras = returnedIntent.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
drawView.drawImage(imageBitmap);
}
}
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (savedInstanceState != null) {
if (savedInstanceState.containsKey("drawCanvas")) {
drawView.setDrawCanvas((SerializableCanvas)savedInstanceState.getSerializable("drawCanvas"));
}
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("drawCanvas", drawView.getDrawCanvas());
}
}

绘图视图类:

public class DrawingView extends View implements Serializable{
private Path drawPath;
private Paint drawPaint;
private Paint canvasPaint;
private int paintColor = 0xFFFF0000;
private SerializableCanvas drawCanvas;
private Bitmap canvasBitmap;
private float brushSize;
private float lastBrushSize;
private boolean erase = false;
public DrawingView(Context context, AttributeSet attrs){
super(context, attrs);
setupDrawing();
}
private void setupDrawing(){
brushSize = getResources().getInteger(R.integer.medium_size);
lastBrushSize = brushSize;
drawPath = new Path();
drawPaint = new Paint();
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(brushSize);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(touchX, touchY);
break;
case MotionEvent.ACTION_MOVE:
drawPath.lineTo(touchX, touchY);
if(erase){
drawCanvas.drawPath(drawPath, drawPaint);
}
break;
case MotionEvent.ACTION_UP:
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
break;
default:
return false;
}
invalidate();
return true;
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
if(erase){ return;}
canvas.drawPath(drawPath, drawPaint);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
drawCanvas = new SerializableCanvas(canvasBitmap);
}
public void setColor(String newColor){
invalidate();
paintColor = Color.parseColor(newColor);
drawPaint.setColor(paintColor);
}
public void setBrushSize(float newSize){
float pixelAmount = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
newSize, getResources().getDisplayMetrics());
brushSize = pixelAmount;
drawPaint.setStrokeWidth(brushSize);
}
public void setLastBrushSize(float lastSize){
lastBrushSize=lastSize;
}
public float getLastBrushSize(){
return lastBrushSize;
}
public void setErase(boolean erase){
this.erase = erase;
if(erase) {
drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
} else {
drawPaint.setXfermode(null);
}
}
public void startNew(){
drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
invalidate();
}
public void drawImage(Bitmap image) {
drawCanvas.drawBitmap(resize(image, drawCanvas.getWidth(), drawCanvas.getHeight()), 0, 0, canvasPaint);
invalidate();
}
public static Bitmap drawableToBitmap (Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable)drawable).getBitmap();
}
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
private static Bitmap resize(Bitmap image, int maxWidth, int maxHeight) {
image = rotateImage(image, 90);
image = Bitmap.createScaledBitmap(image, maxWidth, maxHeight, true);
return image;
}
public static Bitmap rotateImage(Bitmap source, float angle) {
Matrix matrix = new Matrix();
matrix.postRotate(angle);
return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(),
matrix, true);
}
public SerializableCanvas getDrawCanvas(){
return drawCanvas;
}
public void setDrawCanvas(SerializableCanvas drawCanvas){
this.drawCanvas = drawCanvas;
}
public Bitmap getCanvasBitmap(){
return canvasBitmap;
}
public void setCanvasBitmap(Bitmap canvasBitmap){
this.canvasBitmap = canvasBitmap;
}
public Paint getCanvasPaint(){
return canvasPaint;
}
public void setCanvasPaint(Paint canvasPaint){
this.canvasPaint = canvasPaint;
}
}

你是绝对正确的;你的NPE的根本原因是你的活动被关闭了。最有可能的是,"相机"应用强制横向,并且您的活动(不支持配置更改)会重新启动(可能多次)以考虑此"旋转"。另一种常见情况是系统决定关闭你的应用,因为相机应用需要更多的 RAM。

无论如何,您不能在onSaveInstanceState()捆绑包中保存/恢复画布或视图。活动恢复后,必须连接到新的绘图视图及其绘图画布

问题是onActivityResult()可能会在活动恢复之前被调用,这意味着当您收到位图时可能无法绘制位图。在DrawingView.drawBitmap()中,如果drawingCanvas == null,则将位图保存到局部变量,并在画布可用时立即绘制此位图。

PS请注意,对于CAMERA_INTENT_CALLED您的应用程序将绘制相机拍摄的图片的低分辨率缩略图位图。如果需要完整质量的图像,则必须从"相机"应用创建的文件中检索它。

下面是一段用于 DrawingView实现延迟绘制的代码:

private Bitmap savedBitmap;
public void drawImage(Bitmap image) {
if (drawCanvas == null) {
savedBitmap = image;
}
else {
drawCanvas.drawBitmap(resize(image, drawCanvas.getWidth(), drawCanvas.getHeight()), 0, 0, canvasPaint);
invalidate();
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
drawCanvas = new SerializableCanvas(canvasBitmap);
if (savedBitmap != null) {
drawBitmap(savedBitmap);
savedBitmap = null;
}
}

请注意,您不需要对画布或绘图视图进行序列化。

最新更新