Aplicación de cámara de trabajo simple que evita el problema de intención nula
- todo el código modificado incluido en esta respuesta; cerca del tutorial de Android
He pasado mucho tiempo en este tema, así que decidí crear una cuenta y compartir mis resultados con usted.
El tutorial oficial de Android "Taking Photos Simply" resultó no cumplir lo que prometía. El código provisto allí no funcionaba en mi dispositivo: un Samsung Galaxy S4 Mini GT-I9195 con la versión de Android 4.4.2 / KitKat / API Nivel 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 la intención posteriormente atrapada por onActivityResult
ser nula.
Para resolver este problema, obtuve mucha inspiración de las respuestas anteriores aquí y algunas publicaciones útiles en github (principalmente esta de deepwinter , muchas gracias a él; es posible que desee ver su respuesta en una publicación estrechamente relacionada ).
Siguiendo estos consejos agradables, elegí la estrategia de eliminar la putExtra
línea mencionada y hacer lo correspondiente 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 las personas en la misma situación que yo cuando me topé con este problema, ya que las sugerencias de ayuda actuales se refieren principalmente a publicaciones de Github bastante extensas que hacen lo que se trata pero que 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, principalmente en relación con los permisos, tuvieron que agregarse al archivo de manifiesto.
También podría ser valioso señalar que la importación automática de Android Studio puede no ser capaz de manejar java.text.SimpleDateFormat
y java.util.Date
. Tuve que importarlos a ambos manualmente.