Me tomó un tiempo para que funcione y he hecho varias cosas y finalmente funciona. No puedo decir con certeza cuál de las cosas que hice es la solución al problema, pero todas juntas forman la solución de trabajo.
Existen varias razones por las cuales la actividad de la cámara no regresa. Dos más importantes son:
ruta para la nueva imagen no es válida o no existente, o que no se pueden crear
aplicación trayectoria fue suspendido y se guarda perderse.
Así que aquí está mi código para resolver todos estos problemas, todos juntos trabajando.
Primero creé clase de ayuda ImageServices
:
class ImageServices {
private static String getTempDirectoryPath(Context ctx) {
File cache;
// SD Card Mounted
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
cache = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
"/Android/data/" + ctx.getPackageName() + "/cache/");
}
// Use internal storage
else {
cache = ctx.getCacheDir();
}
// Create the cache directory if it doesn't exist
if (!cache.exists()) {
cache.mkdirs();
}
return cache.getAbsolutePath();
}
public static Uri getOutputImageFileUri(Context ctx) {
// TODO: check the presence of SDCard
String tstamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File file = new File(getTempDirectoryPath(ctx), "IMG_" + tstamp + ".jpg");
return Uri.fromFile(file);
}
}
El código está inspirado en parte por developer.android.com y en parte por CameraLauncher class del proyecto Apache Cordova.
En mi actividad al controlador de eventos para el botón para tomar una imagen se ve así:
private Uri imageFileUri;
private static final int MAKE_PHOTO_RESULT_CODE = 100;
private static final int PICK_PHOTO_RESULT_CODE = 101;
public void onMakePhoto(View v) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
imageFileUri = ImageServices.getOutputImageFileUri(this);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageFileUri);
Log.i("babies", "Taking picture: requested " + imageFileUri);
startActivityForResult(intent, MAKE_PHOTO_RESULT_CODE);
}
Método onActivityResult
en realidad no contiene mucho, ya que imageFileUri ya apunta al archivo existente y la representación necesaria se realiza en onResume
método, que se llama cuando la actividad se pone de nuevo en primer plano:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
switch(requestCode) {
case MAKE_PHOTO_RESULT_CODE:
assert imageFileUri != null;
break;
case ...
...other cases...
break;
}
}
}
Pero esto todavía no es suficiente, ya que se pierde imageFileUri
como su aplicación se suspende. Y en dispositivos regulares, las posibilidades son cercanas al 100%.Así que la próxima que necesita para almacenar el valor de imageFileUri
al estado de la instancia:
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (imageFileUri == null) {
outState.putString("file-uri", "");
}
else {
outState.putString("file-uri", imageFileUri.toString());
}
};
y cargarlo de nuevo en - más fácil es directamente en onCreate
:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if (savedInstanceState != null) {
String fileUri = savedInstanceState.getString("file-uri");
if (!fileUri.equals("")) imageFileUri = Uri.parse(fileUri);
}
}
Así, de nuevo, en la parte superior de muchas otras soluciones presentada en este sitio, así como en otras partes, hay dos diferencias principales:
- inteligente
getTempDirectoryPath
inspirado en Apache Cordova
- permitiendo
imageFileUri
para sobrevivir aplicación suspendida
Y ahora - al menos para mí - todo funciona bien.
Olvidó llamar a 'Toast.show();' inside 'onActivityResult()'. Debe ser 'Toast.makeText (this," ¡Registrado con éxito! ", Toast.LENGTH_LONG) .show();' –