2011-10-11 36 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カード上のlocの代わりにgetCacheDirを使用すると、写真は決して保存されないようです。これはキャッシュディレクトリとイメージキャプチャの制限ですか?

答えて

41

技術的には、カメラアプリケーションを使用して画像をキャプチャする場合、内部ストレージへの書き込みはサポートされていないためです。実際、Writing to internal storage is not supportedと書かれているlogcatに例外が書かれています。しかし、これがうまくいかない本当の理由は、デフォルトではアプリケーションパッケージ専用のファイルを作成していて、他のアプリケーション(カメラアプリ)はそのファイルの場所にアクセスできません。そうする。外部ストレージは、ファイルシステムのグローバルにアクセス可能な唯一の部分です。

回避策は、グローバル(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. Application要素にマニフェストであなたの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は、Camera Intentを使用して内部的に画像を保存する最良のソリューションです。 – tagy22

+0

FileProvideの 'READ_EXTERNAL_STORAGE'アクセス権が必要ですか?私はそれが正しいとは思わない。 –

+0

マーティン、私はあなたが正しいと思います。私は私の答えを変えます。 – Harry

関連する問題