2011-10-11 18 views
18

Ho usato con successo questo snippet di codice prima, ma con il file che punta a qualche parte sulla scheda SD.Camera Intent che non salva 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); 

Tuttavia quando uso getCacheDir invece di una posizione sulla scheda SD, sembra che la foto non venga mai salvata. Si tratta di una limitazione di cache dir e acquisizione di immagini?

risposta

41

Tecnicamente, questo è dovuto al fatto che la scrittura nella memoria interna non è supportata quando si utilizza l'applicazione Fotocamera per acquisire un'immagine. In effetti, potresti notare un'eccezione stampata nel logcat che indica Writing to internal storage is not supported. Tuttavia, il vero motivo per cui questo non funziona è che di default si sta creando un file privato per il pacchetto dell'applicazione e un'altra applicazione (ad esempio l'app Fotocamera) non può accedere a tale percorso perché non dispone dell'autorizzazione per fare così. La memoria esterna è l'unica porzione globalmente accessibile del filesystem.

Per risolvere questo problema è necessario creare il file con autorizzazioni globali (WORLD_WRITEABLE). In genere, ciò consente all'app Fotocamera di accedere al file tramite l'Uri passato. Ci non sono realmente i metodi per farlo direttamente sul File, quindi bisogna creare il file utilizzando i metodi disponibili in Context e poi afferrare una maniglia ad essa in seguito:

//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"); 

anche questo genere di limiti in cui è possibile posizionare il file poiché i metodi Context creano intrinsecamente i file nella directory "file" di root e non è possibile reindirizzarlo alla directory della cache.

HTH

+0

Grande, ho avuto la sensazione che era il problema . Penso che mi limiterò a spostare temporaneamente le foto salvandole sulla scheda SD, ma aggiungerò questo al mio toolkit :) – sgarman

+1

Qualche idea su come risolvere la deprecazione Context.MODE_WORLD_WRITEABLE? – superbre

+6

Da [qui] (http://developer.android.com/reference/android/content/Context.html): ** MODE_WORLD_WRITEABLE Questa costante è stata dichiarata obsoleta al livello API 17. La creazione di file scrivibili in tutto il mondo è molto pericolosa e verosimile causare buchi di sicurezza nelle applicazioni.È fortemente scoraggiato; ** – Atul

25

soluzione migliore che ho trovato è: FileProvider (ha bisogno di sostegno-biblioteca-v4) Esso utilizza la memoria interna! https://developer.android.com/reference/android/support/v4/content/FileProvider.html

  1. definire il tuo FileProvider a manifestarsi in elemento di applicazione:

    <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. aggiungere le autorizzazioni in elemento radice manifesta:

    <uses-permission android:name="android.permission.CAMERA" /> 
    <uses-feature android:name="android.hardware.camera" android:required="false" /> 
    
  3. definire i tuoi percorsi delle immagini, per esempio sui 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 di cattura intento:

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

Accetto FileProvide è la soluzione migliore per salvare un'immagine internamente utilizzando l'intento della fotocamera. – tagy22

+0

Sei sicuro di aver bisogno dell'autorizzazione 'READ_EXTERNAL_STORAGE' per FileProvide? Non credo sia corretto. –

+0

Martin, penso che tu abbia ragione. Cambierò la mia risposta – Harry

Problemi correlati