1. 程式人生 > >呼叫系統相機拍照--是配到android-7.0

呼叫系統相機拍照--是配到android-7.0

一:獲取縮放圖

直接呼叫相機拍照,無需人和許可權,但是缺點是隻能獲取到縮放圖(不清晰的哦,一般不採用這種)

        /**
         * 縮放圖
         */
        mThumbnail.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                if
(takePictureIntent.resolveActivity(getPackageManager()) != null) {//判斷是否有相機應用 startActivityForResult(takePictureIntent, REQ_THUMB); } } }); //返回的activity case REQ_THUMB://返回結果 if (resultCode != Activity.RESULT_OK) return; Bundle extras = data.getExtras(); Bitmap imageBitmap = (Bitmap) extras.get("data"
); mImageView.setImageBitmap(imageBitmap); break;

二:儲存全尺寸照片

調取相機拍照儲存一個全尺寸的照片,必須提供完整的檔名,相機應用自動儲存照片。此時也無需任何許可權,建立一個空的臨時檔案用來儲存圖片,使用日期時間戳新照片返回一個唯一的檔名

    String mCurrentPhotoPath;
    private File createImageFile() throws IOException {
        // Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(new Date()); String imageFileName = "JPEG_" + timeStamp + "_"; //.getExternalFilesDir()方法可以獲取到 SDCard/Android/data/你的應用的包名/files/ 目錄,一般放一些長時間儲存的資料 File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); //建立臨時檔案,檔案字首不能少於三個字元,字尾如果為空預設未".tmp" File image = File.createTempFile( imageFileName, /* 字首 */ ".jpg", /* 字尾 */ storageDir /* 資料夾 */ ); mCurrentPhotoPath = "file:" + image.getAbsolutePath(); return image; }

他每次建立都會,建立一個空的檔案

利用上述方法建立的檔案只能是自己的app訪問,隨著app的解除安裝,檔案也會刪除。對於Android N以下,檔案直接Uri.fromFile(file)就可以直接使用,Audroid N 即編譯app的版本 compileSdkVersion 24時,此時會報出FileUriExposedException異常,解釋如下:

對於面向 Android N 的應用,Android 框架執行的 StrictMode,API 禁止向您的應用外公開 file://URI。
如果一項包含檔案 URI 的 Intent 離開您的應用,應用失敗,並出現 FileUriExposedException異常。

若要在應用間共享檔案,您應傳送一項 content://URI,並授予 URI 臨時訪問許可權。
進行此授權的最簡單方式是使用 FileProvider類。 如需有關許可權和共享檔案的更多資訊,
請參閱共享檔案。

  Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        // Ensure that there's a camera activity to handle the intent
        if (takePictureIntent.resolveActivity(getPackageManager()) != null) {//判斷是否有相機應用
            // Create the File where the photo should go
            File photoFile = null;
            try {
                photoFile = createImageFile();//建立臨時圖片檔案
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            // Continue only if the File was successfully created
            if (photoFile != null) {
                //FileProvider 是一個特殊的 ContentProvider 的子類,
                //它使用 content:// Uri 代替了 file:/// Uri. ,更便利而且安全的為另一個app分享檔案
                Uri photoURI = FileProvider.getUriForFile(this,
                        "com.example.android.fileprovider",
                        photoFile);
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
                startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
            }
        }

現在,需要配置FileProvider。在應用程式的清單,提供者新增到您的應用程式,authorities=”applicationId.fileprovider”,使用時

 //FileProvider 是一個特殊的 ContentProvider 的子類,
                        //它使用 content:// Uri 代替了 file:/// Uri. ,更便利而且安全的為另一個app分享檔案
                        Uri photoURI = FileProvider.getUriForFile(MainActivity.this,
                                "com.youga.fileprovider",
                                photoFile);

清單中authorities 和 引數authority保持一致。

  <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.youga.capturingphotos.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths"/>
        </provider>
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images" path="Android/data/com.youga.capturingphotos.name/files/Pictures" />
</paths>
   @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case REQUEST_TAKE_PHOTO://返回結果
                if (resultCode != Activity.RESULT_OK) return;
                mImageView.setImageBitmap(BitmapFactory.decodeFile(mCurrentPhotoPath));
                break;
        }
    }

關於FileProvider

FileProvider 是 ContentProvider 的一個特殊的子類,它有利於安全地分享應用相關的檔案,通過對一個檔案建立content:// Uri而不是file:/// Uri。

由於FileProvider的預設功能包括檔案的content URI的生成,你並不需要在程式碼中定義一個子類。相反,你可以在你的應用中包含一個FileProvider通過在XML檔案中指定它。對於指定FileProvider,新增一個元素在你應用的清單檔案中。設定android:name屬性為android.support.v4.content.FileProvider。根據你控制的域名設定android:authorities屬性為一個URI authority(authorities可以隨意填寫,但是要保證使用時與authority保持一致,推薦applicationId.fileprovider,以免定義重複)。設定android:exported屬性為false;FileProvider不需要公開。設定android:grantUriPermissions屬性為true,為了允許你進行臨時訪問檔案的授權。

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.youga.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths"/>
</provider>

一個FileProvider只能生成一個content URI 對應你事先指定目錄下的檔案。對於指定一個目錄,使用元素的子元素,在XML中指定它的儲存區域和路徑。例如,下面的paths元素告訴FileProvider你打算請求你的私有檔案區域的 images/ 子目錄的content URIs

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images" path="Android/data/com.youga.capturingphotos/files/Pictures/" />
    <external-path name="images" path="Pictures/" />
</paths>

file-path 表示你應用內部儲存區域的檔案的子目錄。這個子目錄和getFilesDir()的返回值一樣。external-path 表示你應用外部儲存區域的檔案的子目錄。這個子目錄和getExternalFilesDir()的返回值一樣。cache-path 表示你應用內部儲存區域的快取子目錄。這個子目錄的根目錄和getCacheDir()的返回值一樣。(如果你修改了provider和paths中的值,需要把應用解除安裝重灌或者開關機一下才能看到變化。)

三:照片新增到相簿

上述儲存全尺寸圖片時,建立圖片臨時檔案在目錄getExternalFilesDir()中,相簿無法訪問到,我們可以直接建立檔案在Environment.getExternalStorageDirectory()目錄下;然後傳送一個廣播讓相簿更新就好了。當然也可以直接建立檔案在相簿目錄下(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)),即DCIM。此時需要SD卡讀寫許可權。

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
File path = Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_DCIM);
// Create an image file name
Log.i(TAG, "path:" + path.getAbsolutePath());
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(new Date());
String imageFileName = "JPEG_" + timeStamp;
File image = File.createTempFile(
        imageFileName,  /* 字首 */
        ".jpg",         /* 字尾 */
        path      /* 資料夾 */
);
mPublicPhotoPath = image.getAbsolutePath();

同時傳送廣播

Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(mPublicPhotoPath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
sendBroadcast(mediaScanIntent);

可以去參考他的原始碼:githubhttps://github.com/YougaKing/CapturingPhotos