studio - Cámara Android: la intención de datos devuelve nulo
startactivityforresult camera (7)
Aplicación de cámara de trabajo simple que evita el problema de intento nulo
- todo el código modificado incluido en esta respuesta; cerca de tutorial de Android
Estuve pasando mucho tiempo sobre este tema, así que decidí crear una cuenta y compartir mis resultados contigo.
El tutorial oficial de Android "Taking Photos Simply" resultó no ser lo que prometía. El código provisto allí no funcionaba en mi dispositivo: un Samsung Galaxy S4 Mini GT-I9195 con Android 4.4.2 / KitKat / API Level 19.
Descubrí que el problema principal era la siguiente línea en el método invocado al capturar la foto ( dispatchTakePictureIntent
en el tutorial):
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
Resultó en el intento subsecuentemente atrapado por onActivityResult
siendo nulo.
Para resolver este problema, saqué mucha inspiración de las respuestas anteriores aquí y algunos mensajes útiles sobre github (sobre todo este de deepwinter , gracias a él, tal vez desee consultar su respuesta en una post estrechamente relacionada también).
Siguiendo estos agradables consejos, elegí la estrategia de eliminar la mencionada línea putExtra
y hacer lo que correspondía para recuperar la imagen tomada de la cámara dentro del método onActivityResult (). Las líneas de código decisivas para recuperar el mapa de bits asociado con la imagen son:
Uri uri = intent.getData();
Bitmap bitmap = null;
try {
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
} catch (IOException e) {
e.printStackTrace();
}
Creé una aplicación ejemplar que solo tiene la capacidad de tomar una foto, guardarla en la tarjeta SD y mostrarla. Creo que esto podría ser útil para personas en la misma situación que yo cuando tropecé con este tema, ya que las sugerencias de ayuda actuales se refieren principalmente a publicaciones github bastante extensas que hacen lo que se pregunta pero no son demasiado fáciles de supervisar para novatos como yo. Con respecto al sistema de archivos que Android Studio crea por defecto al crear un nuevo proyecto, solo tuve que cambiar tres archivos para mi propósito:
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.android.simpleworkingcameraapp.MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="takePicAndDisplayIt"
android:text="Take a pic and display it." />
<ImageView
android:id="@+id/image1"
android:layout_width="match_parent"
android:layout_height="200dp" />
</LinearLayout>
MainActivity.java:
package com.example.android.simpleworkingcameraapp;
import android.content.Intent;
import android.graphics.Bitmap;
import android.media.Image;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MainActivity extends AppCompatActivity {
private ImageView image;
static final int REQUEST_TAKE_PHOTO = 1;
String mCurrentPhotoPath;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
image = (ImageView) findViewById(R.id.image1);
}
// copied from the android development pages; just added a Toast to show the storage location
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmm").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = image.getAbsolutePath();
Toast.makeText(this, mCurrentPhotoPath, Toast.LENGTH_LONG).show();
return image;
}
public void takePicAndDisplayIt(View view) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (intent.resolveActivity(getPackageManager()) != null) {
File file = null;
try {
file = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
}
startActivityForResult(intent, REQUEST_TAKE_PHOTO);
}
}
@Override
protected void onActivityResult(int requestCode, int resultcode, Intent intent) {
if (requestCode == REQUEST_TAKE_PHOTO && resultcode == RESULT_OK) {
Uri uri = intent.getData();
Bitmap bitmap = null;
try {
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
} catch (IOException e) {
e.printStackTrace();
}
image.setImageBitmap(bitmap);
}
}
}
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.simpleworkingcameraapp">
<!--only added paragraph-->
<uses-feature
android:name="android.hardware.camera"
android:required="true" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- only crucial line to add; for me it still worked without the other lines in this paragraph -->
<uses-permission android:name="android.permission.CAMERA" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Tenga en cuenta que la solución que encontré para el problema también condujo a una simplificación del archivo de manifiesto de Android: los cambios sugeridos por el tutorial de Android en términos de agregar un proveedor ya no son necesarios ya que no estoy utilizando ninguno en mi código de Java. Por lo tanto, solo unas pocas líneas estándar -sobre todo con respecto a los permisos- tuvieron que agregarse al archivo de manifiesto.
También podría ser valioso señalar que la autoimportación de Android Studio puede no ser capaz de manejar java.text.SimpleDateFormat
y java.util.Date
. Tuve que importarlos a ambos manualmente.
Tengo una aplicación para Android que contiene múltiples actividades.
En uno de ellos estoy usando un botón que llamará a la cámara del dispositivo:
public void onClick(View view) {
Intent photoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(photoIntent, IMAGE_CAPTURE);
}
En la misma actividad, llamo al método OnActivityResult
para el resultado de la imagen:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == IMAGE_CAPTURE) {
if (resultCode == RESULT_OK) {
Bitmap image = (Bitmap) data.getExtras().get("data");
ImageView imageview = (ImageView) findViewById(R.id.pic);
imageview.setImageBitmap(image);
} else if (resultCode == RESULT_CANCELED) {
Toast.makeText(this, "CANCELED ", Toast.LENGTH_LONG).show();
}
}
}
El problema es que los data
intención son nulos y el método OnActivityResult
se dirige directamente a (resultCode == RESULT_CANCELED)
y la aplicación vuelve a la actividad anterior.
¿Cómo puedo solucionar este problema y, después de llamar a la cámara, la aplicación vuelve a la actividad actual que contiene un ImageView
que contendrá la imagen tomada?
Gracias
El siguiente código funciona para mí:
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, 2);
Y aqui esta el resultado:
protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent)
{
super.onActivityResult(requestCode, resultCode, imageReturnedIntent);
if(resultCode == RESULT_OK)
{
Uri selectedImage = imageReturnedIntent.getData();
ImageView photo = (ImageView) findViewById(R.id.add_contact_label_photo);
Bitmap mBitmap = null;
try
{
mBitmap = Media.getBitmap(this.getContentResolver(), selectedImage);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
Encontré una respuesta fácil. ¡¡funciona!!
o
private void openCameraForResult(int requestCode){
Intent photo = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri uri = Uri.parse("file:///sdcard/photo.jpg");
photo.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(photo,requestCode);
}
if (requestCode == CAMERA_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
File file = new File(Environment.getExternalStorageDirectory().getPath(), "photo.jpg");
Uri uri = Uri.fromFile(file);
Bitmap bitmap;
try {
bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
bitmap = crupAndScale(bitmap, 300); // if you mind scaling
pofileImageView.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
si desea recortar y escalar esta imagen
public static Bitmap crupAndScale (Bitmap source,int scale){
int factor = source.getHeight() <= source.getWidth() ? source.getHeight(): source.getWidth();
int longer = source.getHeight() >= source.getWidth() ? source.getHeight(): source.getWidth();
int x = source.getHeight() >= source.getWidth() ?0:(longer-factor)/2;
int y = source.getHeight() <= source.getWidth() ?0:(longer-factor)/2;
source = Bitmap.createBitmap(source, x, y, factor, factor);
source = Bitmap.createScaledBitmap(source, scale, scale, false);
return source;
}
Está pasando el código de acción para grabar el video, pero trata el resultado como una foto.
La aplicación de cámara predeterminada de Android devuelve un intento no nulo solo al reenviar una miniatura en el Intento devuelto. Si pasa EXTRA_OUTPUT
con un URI para escribir, devolverá un intento null
y la imagen estará en el URI que pasó.
Puede verificar esto mirando el código fuente de la aplicación de la cámara en GitHub:
Bundle newExtras = new Bundle(); if (mCropValue.equals("circle")) { newExtras.putString("circleCrop", "true"); } if (mSaveUri != null) { newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri); } else { newExtras.putBoolean("return-data", true); }
Supongo que está pasando EXTRA_OUTPUT
alguna manera, o la aplicación de la cámara en su teléfono funciona de manera diferente.
Para acceder a la cámara y tomar fotos y establecer ImageView en Android
Tienes que usar Uri file = Uri.fromFile (getOutputMediaFile ()); para malvavisco
use el enlace a continuación para obtener el camino
Probablemente porque tuviste algo como esto?
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri fileUri = CommonUtilities.getTBCameraOutputMediaFileUri();
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
startActivityForResult(takePictureIntent, 2);
Sin embargo, no debe incluir el resultado adicional en la intención, ya que los datos entran en el URI en lugar de en la variable de datos. Por esa razón, debes tomar las dos líneas en el medio, para que tengas
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(takePictureIntent, 2);
Eso es lo que me causó el problema, espero que haya sido de ayuda.