Reputation: 65
I've been working on this Camera app for a little while now. Basically what I want to do is take a picture(and store it internally), then display that image in the next Activity. The preview works perfectly, but when I hit the Capture button on MainActivity the error "Unfortunately, myApplication has stopped" shows up and the app crashes. AndroidStudio is not giving me any Event Log information either...
Here's the main activity(is something wrong with SendInfo?):
public class MainActivity extends ActionBarActivity {
public final static String EXTRA_MESSAGE = "File_name";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Create an instance of Camera
Camera mCamera = getCameraInstance();
// Create our Preview view and set it as the content of our activity.
CameraPreview mPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
// Add a listener to the Capture button
Button captureButton = (Button) findViewById(R.id.button_capture);
captureButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Camera mCamera = getCameraInstance();
// get an image from the camera
mCamera.takePicture(null, null, mPicture);
}
}
);
}
//////////////////////
public void sendInfo(View view)
{
Intent intent = new Intent(this,show_image.class);
Uri fileUri = getOutputMediaFileUri(1);
intent.putExtra(EXTRA_MESSAGE, fileUri.toString());
startActivity(intent);
}
/////////////////
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
if (pictureFile == null){
Log.d("Logtag:", "Error creating media file, check storage permissions: "
);
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (FileNotFoundException e) {
Log.d("Logtag:", "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d("Logtag:", "Error accessing file: " + e.getMessage());
}
}
};
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/** A safe way to get an instance of the Camera object. */
public Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
}
catch (Exception e){
// Camera is not available (in use or does not exist)
Toast.makeText(getApplicationContext(), "Camera is not available (in use or does not exist)",
Toast.LENGTH_LONG).show();
}
return c; // returns null if camera is unavailable
}
public static final int MEDIA_TYPE_IMAGE = 1;
public static final int MEDIA_TYPE_VIDEO = 2;
/** Create a file Uri for saving an image or video */
private static Uri getOutputMediaFileUri(int type){
return Uri.fromFile(getOutputMediaFile(type));
}
/** Create a File for saving an image or video */
private static File getOutputMediaFile(int type){
// To be safe, you should check that the SDCard is mounted
// using Environment.getExternalStorageState() before doing this.
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "MyCameraApp");
// This locat ion works best if you want the created images to be shared
// between applications and persist after your app has been uninstalled.
// Create the storage directory if it does not exist
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
Log.d("Logtag", "failed to create directory");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
if (type == MEDIA_TYPE_IMAGE){
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg");
} else if(type == MEDIA_TYPE_VIDEO) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"VID_"+ timeStamp + ".mp4");
} else {
return null;
}
return mediaFile;
}
}
And here is the second Activity that should be displaying the image...
public class show_image extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
String stringURI = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);
// Uri uri = Uri.parse(stringURI);
Bitmap bitmap = BitmapFactory.decodeFile(stringURI);
ImageView imageView = new ImageView(this);
imageView.setImageBitmap(bitmap);
setContentView(imageView);
}
public static Bitmap decodeFile(File f, final int maxSize) {
Bitmap b = null;
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
FileInputStream fis = null;
try {
fis = new FileInputStream(f);
BitmapFactory.decodeStream(fis, null, o);
fis.close();
int scale = 1;
if (o.outHeight > maxSize || o.outWidth > maxSize) {
scale = (int) Math.pow(2, (int) Math.round(Math.log(maxSize / (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5)));
}
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
fis = new FileInputStream(f);
b = BitmapFactory.decodeStream(fis, null, o2);
} catch (Exception e) {
Log.e("Logtag", "Error processing bitmap", e);
} finally {
//FileUtil.closeQuietly(fis);
}
return b;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
Output from Log Cat:
02-25 00:53:11.907 13191-13191/edu.ramapo.camer I/System.out﹕ debugger has settled (1480)
02-25 00:53:12.177 13191-13191/edu.ramapo.camer I/dalvikvm﹕ Could not find method android.view.ViewGroup.onNestedScrollAccepted, referenced from method android.support.v7.internal.widget.ActionBarOverlayLayout.onNestedScrollAccepted
02-25 00:53:12.177 13191-13191/edu.ramapo.camer W/dalvikvm﹕ VFY: unable to resolve virtual method 11357: Landroid/view/ViewGroup;.onNestedScrollAccepted (Landroid/view/View;Landroid/view/View;I)V
02-25 00:53:12.177 13191-13191/edu.ramapo.camer D/dalvikvm﹕ VFY: replacing opcode 0x6f at 0x0000
02-25 00:53:12.177 13191-13191/edu.ramapo.camer I/dalvikvm﹕ Could not find method android.view.ViewGroup.onStopNestedScroll, referenced from method android.support.v7.internal.widget.ActionBarOverlayLayout.onStopNestedScroll
02-25 00:53:12.177 13191-13191/edu.ramapo.camer W/dalvikvm﹕ VFY: unable to resolve virtual method 11363: Landroid/view/ViewGroup;.onStopNestedScroll (Landroid/view/View;)V
02-25 00:53:12.177 13191-13191/edu.ramapo.camer D/dalvikvm﹕ VFY: replacing opcode 0x6f at 0x0000
02-25 00:53:12.177 13191-13191/edu.ramapo.camer I/dalvikvm﹕ Could not find method android.support.v7.internal.widget.ActionBarOverlayLayout.stopNestedScroll, referenced from method android.support.v7.internal.widget.ActionBarOverlayLayout.setHideOnContentScrollEnabled
02-25 00:53:12.177 13191-13191/edu.ramapo.camer W/dalvikvm﹕ VFY: unable to resolve virtual method 9047: Landroid/support/v7/internal/widget/ActionBarOverlayLayout;.stopNestedScroll ()V
02-25 00:53:12.177 13191-13191/edu.ramapo.camer D/dalvikvm﹕ VFY: replacing opcode 0x6e at 0x000e
02-25 00:53:12.207 13191-13191/edu.ramapo.camer I/dalvikvm﹕ Could not find method android.content.res.TypedArray.getChangingConfigurations, referenced from method android.support.v7.internal.widget.TintTypedArray.getChangingConfigurations
02-25 00:53:12.207 13191-13191/edu.ramapo.camer W/dalvikvm﹕ VFY: unable to resolve virtual method 365: Landroid/content/res/TypedArray;.getChangingConfigurations ()I
02-25 00:53:12.207 13191-13191/edu.ramapo.camer D/dalvikvm﹕ VFY: replacing opcode 0x6e at 0x0002
02-25 00:53:12.207 13191-13191/edu.ramapo.camer I/dalvikvm﹕ Could not find method android.content.res.TypedArray.getType, referenced from method android.support.v7.internal.widget.TintTypedArray.getType
02-25 00:53:12.207 13191-13191/edu.ramapo.camer W/dalvikvm﹕ VFY: unable to resolve virtual method 387: Landroid/content/res/TypedArray;.getType (I)I
02-25 00:53:12.207 13191-13191/edu.ramapo.camer D/dalvikvm﹕ VFY: replacing opcode 0x6e at 0x0002
02-25 00:53:13.068 13191-13191/edu.ramapo.camer D/libEGL﹕ loaded /system/lib/egl/libEGL_adreno200.so
02-25 00:53:13.068 13191-13191/edu.ramapo.camer D/libEGL﹕ loaded /system/lib/egl/libGLESv1_CM_adreno200.so
02-25 00:53:13.078 13191-13191/edu.ramapo.camer D/libEGL﹕ loaded /system/lib/egl/libGLESv2_adreno200.so
02-25 00:53:13.078 13191-13191/edu.ramapo.camer I/Adreno200-EGL﹕ <qeglDrvAPI_eglInitialize:265>: EGL 1.4 QUALCOMM build: HAREESHG_Nondeterministic_AU+PATCH[ES]_msm8960_JB_1.9.6_MR2_CL3219408_release_ENGG (CL3219408)
Build Date: 09/28/13 Sat
Local Branch: hhh
Remote Branch: quic/jb_1.9.6_1
Local Patches: 8d50ec23e42ef52b570aa6ff1650afac0b503d78 CL3219408: Fix in the Glreadpixels for negative offsets and larger dimensions.
801859126f6ca69482b39a34ca61447e3f7cded8 rb: fix panel settings to clear undrawn/undefined buffers
Reconstruct Branch: LOCAL_PATCH[ES]
02-25 00:53:13.118 13191-13191/edu.ramapo.camer D/OpenGLRenderer﹕ Enabling debug mode 0
02-25 00:53:27.353 13191-13191/edu.ramapo.camer D/Logtag﹕ failed to create directory
02-25 00:53:27.353 13191-13191/edu.ramapo.camer D/Logtag:﹕ Error creating media file, check storage permissions:
Upvotes: 0
Views: 1740
Reputation: 2763
I think the reason for the crash is because you are trying to get the camera instance twice: when your activity is created and when button captureButton
is pressed. When you try to get it the second time, it returns null
because it is already in use by your activity.
You should get the camera instance once before the captureButton
button is pressed and process the picture taken after that.
public class MainActivity extends ActionBarActivity {
public final static String EXTRA_MESSAGE = "File_name";
private Camera mCamera;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Create an instance of Camera
mCamera = getCameraInstance();
// Create our Preview view and set it as the content of our activity.
CameraPreview mPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
// Add a listener to the Capture button
Button captureButton = (Button) findViewById(R.id.button_capture);
captureButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// get an image from the camera
mCamera.takePicture(null, null, mPicture);
}
}
);
}
...
Edit
To move to the next activity when a picture is taken, you could call startActivity
after the Camera.PictureCallback
has saved the byte
array to a file.
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
if (pictureFile == null){
Log.d("Logtag:", "Error creating media file, check storage permissions: "
);
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
Intent intent = new Intent(this,show_image.class);
Uri fileUri = Uri.fromFile(pictureFile);
intent.putExtra(EXTRA_MESSAGE, fileUri.toString());
startActivity(intent);
} catch (FileNotFoundException e) {
Log.d("Logtag:", "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d("Logtag:", "Error accessing file: " + e.getMessage());
}
}
};
...
Edit 2
You need to add this permission to your manifest to store the photo on the device:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
I hope this helps.
Upvotes: 1