2011-10-11 17 views
18

He utilizado con éxito este fragmento de código anteriormente, pero con el archivo apuntando a algún lugar de la tarjeta SD.Intento de la cámara que no guarda la foto

final File temp = new File(getCacheDir(), "temp.jpg"); 
temp.delete(); 
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(temp)); 
startActivityForResult(intent, CONFIG.Intents.Actions.SELECT_CAMERA_PHOTO); 

Sin embargo cuando utilizo getCacheDir en lugar de un loc en la tarjeta SD parece la foto no se guarda. ¿Es esto una limitación del directorio de caché y la captura de imágenes?

Respuesta

41

Técnicamente, esto se debe a que la escritura en el almacenamiento interno no es compatible cuando se utiliza la aplicación de la cámara para capturar una imagen. De hecho, puede observar una excepción impresa en logcat que indica Writing to internal storage is not supported. Sin embargo, la verdadera razón por la que esto no funciona es porque de forma predeterminada está creando un archivo que es privado para su paquete de aplicación y otra aplicación (es decir, la aplicación de cámara) no puede acceder a esa ubicación de archivo porque no tiene permiso para hazlo. El almacenamiento externo es la única parte accesible globalmente del sistema de archivos.

La solución alternativa es que cree el archivo con permisos globales (WORLD_WRITEABLE). Normalmente, esto permite que la aplicación de la cámara acceda al archivo a través del Uri pasado. Allí no son realmente métodos para hacer esto directamente en File, así que hay que crear el archivo usando los métodos disponibles en Context y luego tomar un identificador para ella después:

//Remove if exists, the file MUST be created using the lines below 
File f = new File(getFilesDir(), "Captured.jpg"); 
f.delete(); 
//Create new file 
FileOutputStream fos = openFileOutput("Captured.jpg", Context.MODE_WORLD_WRITEABLE); 
fos.close(); 
//Get reference to the file 
File f = new File(getFilesDir(), "Captured.jpg"); 

Este tipo de límites también donde se puede coloque el archivo ya que los métodos Context crean inherentemente archivos en el directorio raíz "archivos" y no puede redirigirlos al directorio de caché.

HTH

+0

grande, yo tenía el presentimiento de que era el tema . Creo que voy a mover de nuevo las fotos de guardado temporalmente a la tarjeta SD, pero agregaré esto a mi toolkit :) – sgarman

+1

¿Alguna idea sobre cómo resolver la desaprobación de Context.MODE_WORLD_WRITEABLE? – superbre

+6

Desde [aquí] (http://developer.android.com/reference/android/content/Context.html): ** MODE_WORLD_WRITEABLE Esta constante ha quedado obsoleta en el nivel de API 17. La creación de archivos de escritura mundial es muy peligrosa, y probablemente para causar agujeros de seguridad en las aplicaciones.Se desaconseja encarecidamente; ** – Atul

25

La mejor solución que he encontrado es: FileProvider (necesita apoyo-biblioteca-v4) Utiliza el almacenamiento interno! https://developer.android.com/reference/android/support/v4/content/FileProvider.html

  1. definir su FileProvider de manifiesto en el elemento de aplicación:

    <provider 
         android:name="android.support.v4.content.FileProvider" 
         android:authorities="your.package.name.fileprovider" 
         android:exported="false" 
         android:grantUriPermissions="true" > 
         <meta-data 
           android:name="android.support.FILE_PROVIDER_PATHS" 
           android:resource="@xml/image_path" /> 
    </provider> 
    
  2. Agregar permisos de elemento raíz manifiesta:

    <uses-permission android:name="android.permission.CAMERA" /> 
    <uses-feature android:name="android.hardware.camera" android:required="false" /> 
    
  3. definir sus rutas de imágenes en, por ejemplo res/xml/image_path.xml:

    <paths xmlns:android="http://schemas.android.com/apk/res/android"> 
    <files-path name="captured_image" path="your/path/"/> 
    </paths> 
    
  4. Java:

    private static final int IMAGE_REQUEST_CODE = 1; 
    // your authority, must be the same as in your manifest file 
    private static final String CAPTURE_IMAGE_FILE_PROVIDER = "your.package.name.fileprovider"; 
    

4,1 a Captura:

File path = new File(activity.getFilesDir(), "your/path"); 
    if (!path.exists()) path.mkdirs(); 
    File image = new File(path, "image.jpg"); 
    Uri imageUri = FileProvider.getUriForFile(activity, CAPTURE_IMAGE_FILE_PROVIDER, image); 
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
    intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); 
    startActivityForResult(intent, IMAGE_REQUEST_CODE); 

4,2 onActivityResult():

@Override 
    public void onActivityResult(int requestCode, int resultCode, Intent intent) { 
     if (requestCode == IMAGE_REQUEST_CODE) { 
      if (resultCode == Activity.RESULT_OK) { 
       File path = new File(getFilesDir(), "your/path"); 
       if (!path.exists()) path.mkdirs(); 
       File imageFile = new File(path, "image.jpg"); 
       // use imageFile to open your image 
      } 
     } 
     super.onActivityResult(requestCode, resultCode, intent); 
    } 
+0

De acuerdo FileProvide es la mejor solución para guardar una imagen internamente usando Camera Intent. – tagy22

+0

¿Estás seguro de que necesitas el permiso 'READ_EXTERNAL_STORAGE' para FileProvide? No creo que sea correcto. –

+0

Martin, creo que tienes razón. Cambiaré mi respuesta. – Harry

Cuestiones relacionadas