2011-10-11 148 views
18

我成功地使用過此代碼片段,但文件指向SD卡上的某處。相機意圖不保存照片

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

然而,當我在SD卡上使用,而不是祿getCacheDir似乎照片不會被保存。這是緩存目錄和圖像捕獲的限制嗎?

回答

41

從技術上講,這是因爲使用Camera應用程序捕捉圖像時,不支持寫入內部存儲。實際上,您可能會注意到在logcat中打印的異常,說明Writing to internal storage is not supported。但是,這不起作用的真正原因是因爲默認情況下,您創建的文件對於您的應用程序包是私有的,而另一個應用程序(即相機應用程序)無法訪問該文件位置,因爲它沒有權限這樣做。外部存儲是文件系統中唯一全球可訪問的部分。

解決方法是爲您創建具有全局(WORLD_WRITEABLE)權限的文件。通常,這允許相機應用程序通過傳遞的Uri訪問文件。有沒有真正的方法來做到這一點直接File,所以你必須使用Context可用的方法來創建該文件,然後後來抓住它的句柄:在這裏你可以

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

這也有點限制放置文件,因爲Context方法固有地在根目錄「files」目錄中創建文件,並且不能將其重定向到緩存目錄。

HTH

+0

太好了,我有一種預感,是問題。我想我只是將保存的照片暫時移動到SD卡,但我會將其添加到我的工具包:) – sgarman

+1

關於如何解決Context.MODE_WORLD_WRITEABLE棄用的任何想法? – superbre

+6

從[這裏](http://developer.android.com/reference/android/content/Context.html):** MODE_WORLD_WRITEABLE這個常量在API級別17中被棄用。創建世界可寫文件是非常危險的,並且可能在應用程序中造成安全漏洞。它是強烈的不鼓勵; ** – Atul

25
我發現

最好的解決辦法是:FileProvider(需要支持庫-V4) 它使用內部存儲! https://developer.android.com/reference/android/support/v4/content/FileProvider.html

  1. 定義在清單的FileProvider在應用元件:

    <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. 添加權限清單中的根元素:

    <uses-permission android:name="android.permission.CAMERA" /> 
    <uses-feature android:name="android.hardware.camera" android:required="false" /> 
    
  3. 定義在例如水庫的圖像路徑/ 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捕獲意圖:

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

同意FileProvide是使用相機意圖在內部保存圖像的最佳解決方案。 – tagy22

+0

您確定您需要FileProvide的'READ_EXTERNAL_STORAGE'權限嗎?我不相信這是正確的。 –

+0

馬丁,我認爲你是對的。我會改變我的答案。 – Harry