我正在为android开发简单的绘图应用程序。我的目标是:
激活相机后:
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);
}
}
我得到NullPointerException:尝试调用虚拟方法,说我的画布为空。 将照片从画廊加载到画布中工作正常。可能原因是我的活动在激活相机后被销毁,因此我制作了一个包装器以使我的画布可序列化:
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对象,但它太大了,里面有一个Bitmap。 我有2个类:MainActivity和DrawingView。如果同一个人知道如何克服这个问题,我将不胜感激。完整代码如下。
MainActivity类:
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());
}
}
DrawingView类:
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;
}
}
答案 0 :(得分:0)
你是对的;您的NPE的根本原因是您的活动已关闭。最有可能的是,Camera应用程序强制横向显示,并且重新启动(可能不止一次)您的不支持配置更改的活动以解释此“轮换”问题。另一种常见情况是系统决定关闭您的应用程序,因为相机应用程序需要更多内存。
无论如何,您无法在 onSaveInstanceState()的捆绑中保存/恢复Canvas或View。活动恢复后,您必须连接到新的 DrawingView 及其 drawingCanvas 。
可以在Activity恢复之前调用 onActivityResult(),这意味着在收到位图时可能无法绘制位图。在 DrawingView.drawBitmap()中,如果是drawingCanvas == null
,请将位图保存到局部变量,并在画布可用后立即绘制此位图。
PS 请注意,对于CAMERA_INTENT_CALLED,您的应用会绘制相机拍摄的照片的低分辨率缩略图位图。如果您想要完整质量的图像,则必须从Camera应用程序创建的文件中检索它。
以下是 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;
}
}
请注意,您不需要为Canvas或DrawingView进行序列化。