2013-08-02 68 views
2

我一直在這一整天,似乎無法得到它的工作。根據之前從事這項工作的人員,它以前的工作方式。如何讓相機意圖將照片放入內部存儲?

cameraIntent = new Intent("android.media.action.IMAGE_CAPTURE"); 
     String imageName = CustomApp.getTimeStamp(0) ; 
     String path = CustomApp.getCurrentActivity().getDir("images", Context.MODE_WORLD_WRITEABLE).getPath()+File.separator+imageName; 

     File file = new File(path) ; 
     Uri img = Uri.fromFile(file) ; 

     Intent passthruDataIntent = new Intent(); 

     cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, img); 
     CustomApp.getCurrentActivity().startActivityForResult(cameraIntent, CustomConstants.REQUESTCODE_CAMERA); 

類似的代碼已經張貼在這裏,但它似乎並沒有在4.2.2上我的Nexus 4的工作。我嘗試了外部存儲,然後工作正常。任何有關爲什麼它可能無法正常工作的見解將非常有幫助。謝謝。

回答

7

內部存儲對於每個應用程序都是私人的 - 第三方相機應用程序無權寫入您的內部存儲。

+0

看,這正是我一直在向我的老闆爭論的。但不幸的是,因爲上面的代碼在某些時候起作用,他們希望以這種方式保留它。我確實有一個問題需要澄清:'Context.MODE_WORLD_WRITEABLE'。我做了一個假設,它允許任何應用程序從那裏訪問文件和內容,因爲它不是'MODE_PRIVATE'。這種方式不行嗎?基本上,因爲它在某個時刻起作用,我會猜測它做了什麼。 – Andy

+1

@Andy:「但不幸的是,因爲上面的代碼在某種程度上起作用,他們希望以這種方式保留它」 - 如果有的話,它肯定無法可靠地工作。 「這種方式不行嗎?」 - 是和不是。是的,該文件是可寫的。您認爲相機應用正在寫入現有文件。它可能會嘗試刪除現有文件並創建一個新文件。 *目錄*是世界可寫的,它們可能會成功刪除,但是您將無法讀取結果文件,因爲它將由其他應用程序擁有,可能是私有的。 – CommonsWare

+2

@Andy:請記住,有數千個相機應用程序,其中任何一個都可以響應你的'Intent',因此行爲會有所不同。僅僅因爲你可以獲得一個應用程序的工作並不意味着所有人都會。 – CommonsWare

1

我有同樣的問題。我通過首先將照片保存在外部存儲器上然後複製到內部存儲器來解決這個問題。希望這可以幫助。

+0

對於SD卡不可用的情況,請參閱http://stackoverflow.com/questions/7720383/camera-intent-not-saving-photo –

4

我在爲同樣的問題而戰,並在很久後得到了一個問題的解決方案,但我相信這可能對社區有用。

隨着在Android 6.0/API級別23中引入新的dynamic permissions,主題問題變得尤爲重要,因爲您需要在運行時請求權限並處理用戶的接受和拒絕反應。要使用相機活動,您需要首先請求相應的許可(android.permission.CAMERA)。然後,如果您將圖片存儲在外部目錄中,用戶還需要將相應的權限android.permission.READ_EXTERNAL_STORAGE授予您的應用。在用戶即將執行預期動作時(例如,如果在按下「拍照」按鈕之後出現照相機訪問許可請求),運行時許可請求對於用戶來說似乎是自然的。但是,如果您使用外部存儲器保存照相機圖像,則當您的應用程序拍攝照片時,您需要同時詢問兩個權限:(1)使用照相機和(2)訪問外部存儲器。後者可能令人沮喪,因爲它不一定清楚爲什麼你的應用程序嘗試訪問用戶文件,而用戶只需要拍攝照片。

解決方案允許避免外部存儲並直接保存相機圖片包括使用content providers。按照storage options documentation

Android提供了一個方法可以讓你即使您的私人數據暴露給其他應用程序 - 與內容提供商。內容提供者是一個可選組件,它公開對您的應用程序數據的讀/寫訪問權限,受到您想強加的任何限制。

這正是你所需要的,以允許對相機的活動直接保存圖片到你的應用程序的本地存儲,讓您可以輕鬆地訪問它,然後沒有要求額外的權限(只需要相機訪問被授予)。

提供了一個帶有代碼示例的好文章here。以下通用代碼受本文啓發,在我們的應用程序中用於實現。

內容提供商類:

/** 
* A content provider that allows to store the camera image internally without requesting the 
* permission to access the external storage to take shots. 
*/ 
public class CameraPictureProvider extends ContentProvider { 
    private static final String FILENAME = "picture.jpg"; 

    private static final Uri CONTENT_URI = Uri.parse("content://xyz.example.app/cameraPicture"); 

    @Override 
    public boolean onCreate() { 
     try { 
      File picture = new File(getContext().getFilesDir(), FILENAME); 
      if (!picture.exists()) 
       if (picture.createNewFile()) { 
        getContext().getContentResolver().notifyChange(CONTENT_URI, null); 
        return true; 
       } 
     } catch (IOException | NullPointerException e) { 
      e.printStackTrace(); 
     } 
     return false; 
    } 

    @Nullable 
    @Override 
    public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException { 
     try { 
      File picture = new File(getContext().getFilesDir(), FILENAME); 
      if (!picture.exists()) 
       picture.createNewFile(); 
      return ParcelFileDescriptor.open(picture, ParcelFileDescriptor.MODE_READ_WRITE); 
     } catch (IOException | NullPointerException e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 

    @Nullable 
    @Override 
    public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { 
     return null; 
    } 

    @Nullable 
    @Override 
    public String getType(@NonNull Uri uri) { 
     String lc = uri.getPath().toLowerCase(); 
     if (lc.endsWith(".jpg") || lc.endsWith(".jpeg")) 
      return "image/jpeg"; 
     return null; 
    } 

    @Nullable 
    @Override 
    public Uri insert(@NonNull Uri uri, ContentValues values) { 
     return null; 
    } 

    @Override 
    public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) { 
     return 0; 
    } 

    @Override 
    public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) { 
     return 0; 
    } 
} 

需要內容提供商的應用程序清單中聲明:

<provider android:authorities="xyz.example.app" 
     android:enabled="true" 
     android:exported="true" 
     android:name="xyz.example.app.CameraPictureProvider" /> 

最後,使用內容提供商,以捕捉攝像機圖像,從調用活動調用以下代碼:

Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
// Ensure that there's a camera activity to handle the intent 
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, CameraPictureProvider.CONTENT_URI); 
startActivityForResult(takePictureIntent, 0); 

請不要e相機許可請求需要單獨處理(不在所提供的代碼示例中完成)。

還值得注意的是,只有在使用構建工具版本23或更高版本時才需要處理權限請求。相同的代碼與低級構建工具兼容,並且在您不受運行時權限請求困擾的情況下很有用,但只希望避免使用外部存儲。

+0

嗨,我完全知道你沒有在這篇文章中處理權限。但是,你能提到一些關於這方面的事情嗎?例如 - 我得到「權限拒絕:getCurrentUser()...需要android.permission.INTERACT_ACROSS_USERS」 - 無法在清單中添加。所以我仍然相信它必須要求相機應用程序寫入我的應用程序的內部存儲器......有什麼想法? – marienke

+0

這是一個更好的解決方案。 – YellowJ

相關問題