La cámara androide intenta fallar la aplicación en algunos teléfonos (aproximadamente el 20% de ellos)

He hecho un montón de investigación en este tema y he visto algunas grandes respuestas y encontró algunos buenos recursos de "soluciones" a este problema. Desafortunadamente, sin embargo, todavía estoy encontrando un montón de fallos de la aplicación en ciertos dispositivos. Los accidentes ocurren después de que alguien haya tomado su foto y la intención de la cámara se supone que pasa la información a la actividad de llamada. Para los propósitos de mi aplicación, sólo estoy sobreescribiendo cualquier foto existente con la foto recién tomada, así que puedo usar prácticamente una ruta estática a la ubicación del archivo. Así es como yo llamo la intención:

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // get the file path from an external class (necessary for galaxy nexus) imageFileAndPath = ImageServices.getOutputImageFileUri(cont); intent.putExtra(MediaStore.EXTRA_OUTPUT, imageFileAndPath); startActivityForResult(intent, CAMERA_REQUEST_CODE); 

El imageFileAndPath es sólo una variable de URI y lo estoy creando de una clase separada porque eso resolvió otro problema donde presionar "done" o la marca de verificación o w / e que está en el dispositivo particular para cerrar la intención de la cámara no estaba haciendo nada Varios tipos de dispositivos. Creando el URI de una clase separada, resuelve ese problema por alguna razón desconocida.

Mi onActivityResult se parece a esto:

 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if(resultCode == Activity.RESULT_OK) { if (requestCode == CAMERA_REQUEST_CODE) { setupImageView(); imageView = (ImageView) findViewById(R.id.image_view); webView.setVisibility(View.GONE); imageView.setVisibility(View.VISIBLE); button.setVisibility(View.GONE); reTakePicButton.setVisibility(View.VISIBLE); rl.setVisibility(View.VISIBLE); } } } 

Porque no necesito un camino dinámico para guardar mis fotos (ya que está sobrescribiendo las fotos existentes), simplemente llamo a otro método dentro de mi actividad que cambia el tamaño de la foto y lo rota en consecuencia. Ese método está abajo:

 private void setupImageView() { imageLocation = Environment.getExternalStorageDirectory().getAbsolutePath() + "/myappphoto/myappphoto.jpg"; // Get the dimensions of the View Display display = getWindowManager().getDefaultDisplay(); Point size = getDisplaySize(display); int targetW = size.x; // Get the dimensions of the bitmap BitmapFactory.Options bmOptions = new BitmapFactory.Options(); bmOptions.inJustDecodeBounds = true; BitmapFactory.decodeFile(imageLocation, bmOptions); int photoW = bmOptions.outWidth; int photoH = bmOptions.outHeight; // Determine how much to scale down the image int scaleFactor = Math.min(photoW / targetW, photoH / targetW); // Decode the image file into a Bitmap sized to fill the View bmOptions.inJustDecodeBounds = false; bmOptions.inSampleSize = scaleFactor; bmOptions.inPurgeable = true; Bitmap bitmap = BitmapFactory.decodeFile(imageLocation, bmOptions); int rotationForImage = getRotationForImage(imageLocation); if (rotationForImage != 0) { int targetWidth = rotationForImage == 90 || rotationForImage == 270 ? bitmap.getHeight() : bitmap.getWidth(); int targetHeight = rotationForImage == 90 || rotationForImage == 270 ? bitmap.getWidth() : bitmap.getHeight(); Bitmap rotatedBitmap = Bitmap.createBitmap(targetWidth, targetHeight, bitmap.getConfig()); Canvas canvas = new Canvas(rotatedBitmap); Matrix matrix = new Matrix(); matrix.setRotate(rotationForImage, bitmap.getWidth() / 2, bitmap.getHeight() / 2); canvas.drawBitmap(bitmap, matrix, new Paint()); bitmap.recycle(); bitmap = rotatedBitmap; } Bitmap resized; if(bitmap.getWidth() >= 900 || bitmap.getHeight() >=900) { int newWidth = Math.round(bitmap.getWidth()/2); int newHeight = Math.round(bitmap.getHeight()/2); resized = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true); } else { resized = bitmap; } //bitmap.recycle(); bitmap = resized; ByteArrayOutputStream bytes = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 70, bytes); try { File f = new File(imageLocation); f.createNewFile(); //write the bytes in file FileOutputStream fo = new FileOutputStream(f); fo.write(bytes.toByteArray()); fo.close(); } catch(java.io.IOException e){} imageView.setImageBitmap(bitmap); } 

Puede ver la ruta estática en la parte superior de ese método al archivo de imagen que se guarda de la intención de la cámara.

Supongo que es posible que el cambio de tamaño, el método de rotación está causando los accidentes, pero no veo por qué lo haría, que todo parece bastante java estándar de codificación para mí.

¿Alguien puede ver algo claramente malo con lo que estoy haciendo aquí? Como he dicho en el título de este hilo, mi código está causando accidentes en aproximadamente el 20% de los dispositivos que lo ejecutan que es inaceptable. Puedo manejar 5% pero no 20%.

Me doy cuenta de que el desarrollo de Android es algo así como una pesadilla en este sentido, ya que hay que tener en cuenta tantos tipos de dispositivos diferentes (fabricantes, versiones de android, etc), pero creo que la actividad de la cámara debería ser mejor estandarizado que esto. Como he dicho en la parte superior de este hilo, he hecho un montón de mirar en este tema y visto a varias personas con problemas similares a la mina, pero no una buena resolución que cubre la mayoría de los dispositivos. Realmente no quiero tener que escribir (ni creo que debería tener que escribir) mi propia cámara desde el punto cero. Tiene que haber una mejor implementación de la intención por defecto, la cámara incorporada en los dispositivos Android … Yo no he sido capaz de encontrarlo todavía. Como puede ver, ni siquiera estoy preocupado por la creación dinámica de imágenes que deberían hacer este proyecto más fácil.

TIA

Editar: por el comentario de abajo, he añadido un stacktrace de una cámara que falla. Parece una excepción de puntero nulo. Tomé como 6 imágenes, y seguí volviendo con el botón que llama a la intención de la cámara hasta que finalmente lo consiguió para fallar. Aquí está el rastreo de la pila:

 STACK_TRACE "java.lang.RuntimeException: Unable to resume activity {com.myapp/com.myapp.MyActivity}: java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=904, result=-1, data=null} to activity {com.myapp/com.myapp.MyActivity}: java.lang.NullPointerException at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2124) at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2139) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1672) at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:2836) at android.app.ActivityThread.access$1600(ActivityThread.java:117) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:939) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:130) at android.app.ActivityThread.main(ActivityThread.java:3687) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:507) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:842) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=904, result=-1, data=null} to activity {com.myapp/com.myapp.MyActivity}: java.lang.NullPointerException at android.app.ActivityThread.deliverResults(ActivityThread.java:2536) at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2111) ... 13 more Caused by: java.lang.NullPointerException at com.myapp.MyActivity.onActivityResult(EnterContest.java:257) at android.app.Activity.dispatchActivityResult(Activity.java:3908) at android.app.ActivityThread.deliverResults(ActivityThread.java:2532) ... 14 more java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=904, result=-1, data=null} to activity {com.myapp/com.myapp.MyActivity}: java.lang.NullPointerException at android.app.ActivityThread.deliverResults(ActivityThread.java:2536) at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2111) at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2139) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1672) at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:2836) at android.app.ActivityThread.access$1600(ActivityThread.java:117) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:939) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:130) at android.app.ActivityThread.main(ActivityThread.java:3687) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:507) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:842) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.NullPointerException at com.myapp.MyActivity.onActivityResult(EnterContest.java:257) at android.app.Activity.dispatchActivityResult(Activity.java:3908) at android.app.ActivityThread.deliverResults(ActivityThread.java:2532) ... 14 more java.lang.NullPointerException at com.myapp.MyActivity.onActivityResult(EnterContest.java:257) at android.app.Activity.dispatchActivityResult(Activity.java:3908) at android.app.ActivityThread.deliverResults(ActivityThread.java:2532) at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2111) at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2139) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1672) at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:2836) at android.app.ActivityThread.access$1600(ActivityThread.java:117) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:939) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:130) at android.app.ActivityThread.main(ActivityThread.java:3687) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:507) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:842) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600) at dalvik.system.NativeStart.main(Native Method) 

Tal vez una suposición, pero creo que tenía el mismo problema, lo arreglé leer el mapa de bits en un AsyncTask nuevo y no en el hilo de la interfaz de usuario.

La excepción ocurrió (aparentemente de manera aleatoria) llamando

 getContentResolver().notifyChange(selectedImage, null); 

Donde selectedImage es el URI establecido antes en

 intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo)); 

¿Qué estaba llamando en com.myapp.MyActivity.onActivityResult (EnterContest.java:257)?

Tengo un rastro de pila recopilado con ACRA:

 java.lang.RuntimeException: Unable to resume activity {com.infonair.meetme.app/com.infonair.meetme.activity.photo.TakePhotoActivity}: java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=7898789, result=-1, data=Intent { dat=content://media/external/images/media/9 }} to activity {com.infonair.meetme.app/com.infonair.meetme.activity.photo.TakePhotoActivity}: java.lang.NullPointerException at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2126) at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2141) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1674) at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:2838) at android.app.ActivityThread.access$1600(ActivityThread.java:117) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:935) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:130) at android.app.ActivityThread.main(ActivityThread.java:3737) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:507) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:894) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:652) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=7898789, result=-1, data=Intent { dat=content://media/external/images/media/9 }} to activity {com.infonair.meetme.app/com.infonair.meetme.activity.photo.TakePhotoActivity}: java.lang.NullPointerException at android.app.ActivityThread.deliverResults(ActivityThread.java:2538) at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2113) ... 13 more Caused by: java.lang.NullPointerException at android.os.Parcel.readException(Parcel.java:1328) at android.os.Parcel.readException(Parcel.java:1276) at android.content.IContentService$Stub$Proxy.notifyChange(IContentService.java:458) at android.content.ContentResolver.notifyChange(ContentResolver.java:912) at android.content.ContentResolver.notifyChange(ContentResolver.java:898) at com.infonair.meetme.activity.photo.TakePhotoActivity.onActivityResult(TakePhotoActivity.java:154) at android.app.Activity.dispatchActivityResult(Activity.java:3908) at android.app.ActivityThread.deliverResults(ActivityThread.java:2534) ... 14 more java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=7898789, result=-1, data=Intent { dat=content://media/external/images/media/9 }} to activity {com.infonair.meetme.app/com.infonair.meetme.activity.photo.TakePhotoActivity}: java.lang.NullPointerException at android.app.ActivityThread.deliverResults(ActivityThread.java:2538) at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2113) at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2141) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1674) at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:2838) at android.app.ActivityThread.access$1600(ActivityThread.java:117) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:935) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:130) at android.app.ActivityThread.main(ActivityThread.java:3737) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:507) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:894) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:652) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.NullPointerException at android.os.Parcel.readException(Parcel.java:1328) at android.os.Parcel.readException(Parcel.java:1276) at android.content.IContentService$Stub$Proxy.notifyChange(IContentService.java:458) at android.content.ContentResolver.notifyChange(ContentResolver.java:912) at android.content.ContentResolver.notifyChange(ContentResolver.java:898) at com.infonair.meetme.activity.photo.TakePhotoActivity.onActivityResult(TakePhotoActivity.java:154) at android.app.Activity.dispatchActivityResult(Activity.java:3908) at android.app.ActivityThread.deliverResults(ActivityThread.java:2534) ... 14 more java.lang.NullPointerException at android.os.Parcel.readException(Parcel.java:1328) at android.os.Parcel.readException(Parcel.java:1276) at android.content.IContentService$Stub$Proxy.notifyChange(IContentService.java:458) at android.content.ContentResolver.notifyChange(ContentResolver.java:912) at android.content.ContentResolver.notifyChange(ContentResolver.java:898) at com.infonair.meetme.activity.photo.TakePhotoActivity.onActivityResult(TakePhotoActivity.java:154) at android.app.Activity.dispatchActivityResult(Activity.java:3908) at android.app.ActivityThread.deliverResults(ActivityThread.java:2534) at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2113) at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2141) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1674) at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:2838) at android.app.ActivityThread.access$1600(ActivityThread.java:117) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:935) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:130) at android.app.ActivityThread.main(ActivityThread.java:3737) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:507) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:894) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:652) at dalvik.system.NativeStart.main(Native Method) 

Luchando con este problema me di cuenta de que en algunos dispositivos de la imagen tomada era demasiado grande incluso para mostrarse en un ImageView (había una advertencia acerca de la imagen de ser de ancho para la textura), así que empecé a trabajar en el cambio de tamaño a un servidor utilizable tamaño.

Voy a publicar todo el código (por lo menos el de tomar y manipular la imagen) por si acaso puede ayudar

Aquí está el código para llamar a la intención

  public void takePhoto() { String directoryPath = DCIM_PATH; this.pictureFileName = Long.toHexString(System.currentTimeMillis())+".jpg"; String filePath = directoryPath + pictureFileName ; File directory = new File(directoryPath); if (!directory.exists()) { directory.mkdirs(); } this.imageUri = Uri.parse(filePath); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra( MediaStore.EXTRA_OUTPUT,Uri.fromFile( new File(filePath) ) ); startActivityForResult(intent, TAKE_PICTURE); } 

In onActivityResult Yo llamo un método para hacer frente a la foto recién tomada

  @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case TAKE_PICTURE: if (resultCode == Activity.RESULT_OK) { loadImageJustTaken(imageUri); } break; } } 

Este es dicho método

 public void loadImageJustTaken(Uri selectedImage) { mActivity.getApplicationContext().getContentResolver().notifyChange(selectedImage, null); /* * process image to make its wide equals IMG_WIDTH constant, so that larger images will fit in ImageView */ Bitmap b = BitmapHelper.decodeFileToScaledBitmap(new File(imageUri.getPath()), Tapabook.IMG_WIDTH); ivPicture.setImageBitmap(b); ivPicture.setVisibility(View.VISIBLE); System.gc(); } 

Y aquí está el código de mi clase BitmapHelper

 import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import org.apache.http.entity.mime.content.FileBody; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Environment; import android.util.Log; public class BitmapHelper { private static final String LOGTAG = "BitmapHelper"; public static File scaleBitmapFile(File f, int WIDTH) throws IOException{ Log.d(LOGTAG, "scaleBitmapFile to WIDTH: " + WIDTH); Bitmap b2 = decodeFileToScaledBitmap( f, WIDTH); ByteArrayOutputStream outStream = new ByteArrayOutputStream(); Log.d(LOGTAG, "scaleBitmapFile compress bitmap to jpg "); b2.compress(Bitmap.CompressFormat.JPEG,70 , outStream); File scaledBitmapFile = new File(Environment.getExternalStorageDirectory() + File.separator + "temp.jpg"); Log.d(LOGTAG, "scaleBitmapFile file: temp.jpg" ); scaledBitmapFile.createNewFile(); Log.d(LOGTAG, "scaleBitmapFile file CREATED" ); //write the bytes in file FileOutputStream fo = new FileOutputStream(scaledBitmapFile); fo.write(outStream.toByteArray()); Log.d(LOGTAG, "scaleBitmapFile file WRITTEN" ); // remember close de FileOutput fo.close(); Log.d(LOGTAG, "scaleBitmapFile file CLOSED" ); return scaledBitmapFile; } public static Bitmap decodeFileToScaledBitmap(File f, int WIDTH){ Log.d(LOGTAG, "decodeFileToScaledBitmap to WIDTH: " + WIDTH); try{ //Decode image size BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; BitmapFactory.decodeStream(new FileInputStream(f),null,o); //The new size we want to scale to final int REQUIRED_WIDTH=WIDTH; final int ORIG_WIDTH = o.outWidth; final int ORIG_HEIGHT = o.outHeight; Log.d(LOGTAG, "decodeFileToScaledBitmap original width: [" + ORIG_WIDTH + "] original height: [" + ORIG_HEIGHT+ "]"); final int REQUIRED_HEIGHT = ORIG_HEIGHT/( ORIG_WIDTH / REQUIRED_WIDTH ) ; //Decode with scaled height Log.d(LOGTAG, "decodeFileToScaledBitmap returning scaled bitmap "); return Bitmap.createScaledBitmap( BitmapFactory.decodeFile(f.getAbsolutePath()), REQUIRED_WIDTH, REQUIRED_HEIGHT, false); }catch (FileNotFoundException e) { Log.e(LOGTAG, "decodeFileToScaledBitmap FileNotFoundException: " +e.getMessage()); } return null; } public static Bitmap scaleBitmap(Bitmap b, int WIDTH){ final int REQUIRED_WIDTH=WIDTH; final int ORIG_WIDTH = b.getWidth(); final int ORIG_HEIGHT = b.getHeight(); Log.d(LOGTAG, "scaleBitmap original width: [" + ORIG_WIDTH + "] original height: [" + ORIG_HEIGHT+ "]"); final int REQUIRED_HEIGHT = ORIG_HEIGHT/( ORIG_WIDTH / REQUIRED_WIDTH ) ; Log.d(LOGTAG, "scaleBitmap returning scaled bitmap "); return Bitmap.createScaledBitmap( b, REQUIRED_WIDTH, REQUIRED_HEIGHT, false); } 

}

Al usar esto, ya no tengo problemas al tomar fotografías con dispositivos Samsung, ya sean portátiles antiguos como SG3 / Apollo o tabletas más nuevas como SGTab 10.1 Espero que ayude 🙂

  • Tomar la imagen de la cámara personalizada se estira cuando guardar en ImageView
  • Uso de la cámara del teléfono a través de Intent - ¿la actividad nunca vuelve?
  • ¿Es posible recortar la vista previa de la cámara?
  • Compruebe si el dispositivo tiene una cámara?
  • Capturado La orientación de la fotografía está cambiando en android
  • Cámara predeterminada para tomar una foto en android
  • Utilizar cámara USB en la aplicación de Android
  • MEDIA_TYPE_IMAGE no reconocido
  • La visualización / visualización de la cámara en pantalla completa no mantiene la relación de aspecto: la imagen está sesgada, estirada para encajar en la pantalla
  • NullPointerException en onActivityResult después de llamar a la intención de la cámara
  • Android El enfoque automático no funciona después de crear la vista de cámara
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.