2011-10-11 39 views
18

Tôi đã sử dụng thành công đoạn mã này trước đây, nhưng với tệp trỏ tới đâu đó trên thẻ SD.Máy ảnh Mục đích không lưu ảnh

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

Tuy nhiên khi tôi sử dụng getCacheDir thay vì nằm trên thẻ SD có vẻ như ảnh không bao giờ được lưu. Đây có phải là hạn chế của bộ đệm ẩn và chụp ảnh không?

Trả lời

41

Về mặt kỹ thuật, điều này là do việc ghi vào bộ nhớ trong không được hỗ trợ khi sử dụng ứng dụng Máy ảnh để chụp ảnh. Trong thực tế, bạn có thể nhận thấy một ngoại lệ được in trong logcat ghi rõ số Writing to internal storage is not supported. Tuy nhiên, lý do thực sự không hiệu quả là vì mặc định bạn đang tạo một tệp riêng tư cho gói ứng dụng của mình và một ứng dụng khác (ví dụ ứng dụng Camera) không thể truy cập vị trí tệp đó vì nó không có quyền làm như vậy. Bộ nhớ ngoài là phần duy nhất có thể truy cập trên toàn cầu của hệ thống tệp.

Giải pháp thay thế dành cho bạn là tạo tệp có quyền toàn cầu (WORLD_WRITEABLE). Thông thường, điều này cho phép ứng dụng Máy ảnh truy cập tệp qua Uri đã qua. Không có thực sự phương pháp để làm điều này trực tiếp trên File, vì vậy bạn phải tạo ra các tập tin bằng cách sử dụng phương pháp có sẵn trong Context và sau đó lấy một tay cầm vào nó sau đó:

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

này cũng loại giới hạn nơi bạn có thể đặt tệp từ các phương thức Context vốn đã tạo các tệp trong thư mục "tệp" gốc và bạn không thể chuyển hướng tệp đó vào thư mục bộ nhớ cache.

HTH

+0

Tuyệt vời, tôi đã có một linh cảm đó là vấn đề . Tôi nghĩ rằng tôi sẽ chỉ di chuyển ảnh tạm thời vào thẻ SD một lần nữa, nhưng tôi sẽ thêm nó vào bộ công cụ của tôi :) – sgarman

+1

Bất kỳ ý tưởng nào về cách giải quyết việc sử dụng Context.MODE_WORLD_WRITEABLE? – superbre

+6

Từ [tại đây] (http://developer.android.com/reference/android/content/Context.html): ** MODE_WORLD_WRITEABLE Hằng số này không được chấp nhận ở cấp API 17. Tạo tệp có thể ghi trên thế giới rất nguy hiểm và có khả năng gây ra lỗ hổng bảo mật trong các ứng dụng.Thật không khuyến khích, ** – Atul

25

giải pháp tốt nhất mà tôi tìm thấy là: FileProvider (cần hỗ trợ thư viện-v4) Nó sử dụng bộ nhớ trong! https://developer.android.com/reference/android/support/v4/content/FileProvider.html

  1. Xác định FileProvider của bạn trong Manifest trong phần tử Ứng dụng:

    <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. Add quyền trong phần tử gốc manifest:

    <uses-permission android:name="android.permission.CAMERA" /> 
    <uses-feature android:name="android.hardware.camera" android:required="false" /> 
    
  3. Xác định đường dẫn hình ảnh của bạn trong ví dụ 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 chụp ý:

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

Đồng ý FileProvide là giải pháp tốt nhất để lưu hình ảnh nội bộ bằng Camera Intent. – tagy22

+0

Bạn có chắc là bạn cần sự cho phép của 'READ_EXTERNAL_STORAGE' đối với FileProvide không? Tôi không tin nó đúng. –

+0

Martin, tôi nghĩ bạn đúng. Tôi sẽ thay đổi câu trả lời của tôi. – Harry

Các vấn đề liên quan