Android 調(diào)用相機(jī)拍照,適配到Android 10

今天寫的博客是關(guān)于Android調(diào)用手機(jī)相機(jī)拍照并顯示圖片咖祭。這是一個(gè)很常用的功能掩宜,并且這個(gè)功能在Android6.0、7.0么翰、10.0等版本上實(shí)現(xiàn)都有所不同牺汤,需要對(duì)Android各個(gè)版本進(jìn)行兼容適配,目前最新的Android版本是Android 10浩嫌,所以這篇博客適配到Android 10檐迟。我自己也寫了個(gè)demo,方便以后要使用的時(shí)候直接拿來码耐。

調(diào)用相機(jī)追迟,首先需要申請(qǐng)相機(jī)權(quán)限。

<uses-permission android:name="android.permission.CAMERA" />

android 6.0以后骚腥,相機(jī)權(quán)限需要?jiǎng)討B(tài)申請(qǐng)敦间。

   // 申請(qǐng)相機(jī)權(quán)限的requestCode
   private static final int PERMISSION_CAMERA_REQUEST_CODE = 0x00000012;

   /**
    * 檢查權(quán)限并拍照。
    * 調(diào)用相機(jī)前先檢查權(quán)限束铭。
    */
   private void checkPermissionAndCamera() {
       int hasCameraPermission = ContextCompat.checkSelfPermission(getApplication(),
               Manifest.permission.CAMERA);
       if (hasCameraPermission == PackageManager.PERMISSION_GRANTED) {
           //有調(diào)起相機(jī)拍照廓块。
           openCamera();
       } else {
           //沒有權(quán)限,申請(qǐng)權(quán)限纯露。
           ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.CAMERA},
                   PERMISSION_CAMERA_REQUEST_CODE);
       }
   }

   /**
    * 處理權(quán)限申請(qǐng)的回調(diào)剿骨。
    */
   @Override
   public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
       if (requestCode == PERMISSION_CAMERA_REQUEST_CODE) {
           if (grantResults.length > 0
                   && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
               //允許權(quán)限,有調(diào)起相機(jī)拍照埠褪。
               openCamera();
           } else {
               //拒絕權(quán)限,彈出提示框挤庇。
               Toast.makeText(this,"拍照權(quán)限被拒絕",Toast.LENGTH_LONG).show();
           }
       }
   }

申請(qǐng)權(quán)限后钞速,就可以調(diào)起相機(jī)拍照了。調(diào)用相機(jī)只需要調(diào)用startActivityForResult傳一個(gè)Intent就可以了嫡秕,但是這個(gè)Intent需要傳遞一個(gè)uri渴语,用于保存拍出來的圖片,創(chuàng)建這個(gè)uri時(shí)昆咽,各個(gè)Android版本有所不同驾凶,需要進(jìn)行版本兼容牙甫。

   //用于保存拍照?qǐng)D片的uri
    private Uri mCameraUri;

    // 用于保存圖片的文件路徑,Android 10以下使用圖片路徑訪問圖片
    private String mCameraImagePath;

    // 是否是Android 10以上手機(jī)
    private boolean isAndroidQ = Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q;

    /**
     * 調(diào)起相機(jī)拍照
     */
    private void openCamera() {
        Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        // 判斷是否有相機(jī)
        if (captureIntent.resolveActivity(getPackageManager()) != null) {
            File photoFile = null;
            Uri photoUri = null;

            if (isAndroidQ) {
                // 適配android 10
                photoUri = createImageUri();
            } else {
                try {
                    photoFile = createImageFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                if (photoFile != null) {
                    mCameraImagePath = photoFile.getAbsolutePath();
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        //適配Android 7.0文件權(quán)限调违,通過FileProvider創(chuàng)建一個(gè)content類型的Uri
                        photoUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", photoFile);
                    } else {
                        photoUri = Uri.fromFile(photoFile);
                    }
                }
            }

            mCameraUri = photoUri;
            if (photoUri != null) {
                captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
                captureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                startActivityForResult(captureIntent, CAMERA_REQUEST_CODE);
            }
        }
    }

    /**
     * 創(chuàng)建圖片地址uri,用于保存拍照后的照片 Android 10以后使用這種方法
     */
    private Uri createImageUri() {
        String status = Environment.getExternalStorageState();
        // 判斷是否有SD卡,優(yōu)先使用SD卡存儲(chǔ),當(dāng)沒有SD卡時(shí)使用手機(jī)存儲(chǔ)
        if (status.equals(Environment.MEDIA_MOUNTED)) {
           return getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new ContentValues());
        } else {
            return getContentResolver().insert(MediaStore.Images.Media.INTERNAL_CONTENT_URI, new ContentValues());
        }
    }

    /**
     * 創(chuàng)建保存圖片的文件
     */
    private File createImageFile() throws IOException {
        String imageName = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
        File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        if (!storageDir.exists()) {
            storageDir.mkdir();
        }
        File tempFile = new File(storageDir, imageName);
        if (!Environment.MEDIA_MOUNTED.equals(EnvironmentCompat.getStorageState(tempFile))) {
            return null;
        }
        return tempFile;
    }

接收拍照結(jié)果和顯示圖片

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == CAMERA_REQUEST_CODE) {
            if (resultCode == RESULT_OK) {
                if (isAndroidQ) {
                    // Android 10 使用圖片uri加載
                    ivPhoto.setImageURI(mCameraUri);
                } else {
                    // 使用圖片路徑加載
                    ivPhoto.setImageBitmap(BitmapFactory.decodeFile(mCameraImagePath));
                }
            } else {
                Toast.makeText(this,"取消",Toast.LENGTH_LONG).show();
            }
        }
    }

這兩需要說明一下窟哺,Android 10由于文件權(quán)限的關(guān)系,顯示手機(jī)儲(chǔ)存卡里的圖片不能直接使用圖片路徑技肩,需要使用圖片uri加載且轨。關(guān)于在Android 10顯示手機(jī)圖片的適配可以看我的另外一篇博客:Android 10加載手機(jī)本地圖片

另外雖然我在這篇博客里對(duì)Android 10和10以下的手機(jī)使用了不同的方式創(chuàng)建uri 和加載圖片,但其實(shí)Android 10創(chuàng)建uri的方式和使用uri加載圖片的方式在10以下的手機(jī)是同樣適用的虚婿。

android 7.0需要配置文件共享旋奢。

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

在res目錄下創(chuàng)建文件夾xml ,放置一個(gè)文件file_paths.xml(文件名可以隨便取)然痊,配置需要共享的文件目錄至朗,也就是拍照?qǐng)D片保存的目錄。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <paths>
        <!-- 這個(gè)是保存拍照?qǐng)D片的路徑,必須配置剧浸。 -->
        <external-files-path
            name="images"
            path="Pictures" />
    </paths>
</resources>

如果想把圖片放在手機(jī)的共享儲(chǔ)存區(qū)锹引,比如Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)文件夾下,還需要申請(qǐng)文件讀寫權(quán)限辛蚊。

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

文件讀寫權(quán)限同樣需要?jiǎng)討B(tài)申請(qǐng)粤蝎,申請(qǐng)權(quán)限的方式跟上面申請(qǐng)相機(jī)權(quán)限一樣,這里就不再重復(fù)了袋马。

完整的demo請(qǐng)看我的Github初澎。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市虑凛,隨后出現(xiàn)的幾起案子碑宴,更是在濱河造成了極大的恐慌,老刑警劉巖桑谍,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件延柠,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡锣披,警方通過查閱死者的電腦和手機(jī)贞间,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雹仿,“玉大人增热,你說我怎么就攤上這事‰柿桑” “怎么了峻仇?”我有些...
    開封第一講書人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)邑商。 經(jīng)常有香客問我摄咆,道長(zhǎng)凡蚜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任吭从,我火速辦了婚禮朝蜘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘影锈。我一直安慰自己芹务,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開白布鸭廷。 她就那樣靜靜地躺著枣抱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪辆床。 梳的紋絲不亂的頭發(fā)上佳晶,一...
    開封第一講書人閱讀 51,182評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音讼载,去河邊找鬼轿秧。 笑死,一個(gè)胖子當(dāng)著我的面吹牛咨堤,可吹牛的內(nèi)容都是我干的菇篡。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼一喘,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼驱还!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起凸克,我...
    開封第一講書人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤议蟆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后萎战,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體咐容,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年蚂维,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了戳粒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡虫啥,死狀恐怖享郊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情孝鹊,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布展蒂,位于F島的核電站又活,受9級(jí)特大地震影響苔咪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜柳骄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一团赏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧耐薯,春花似錦舔清、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至臼婆,卻和暖如春抒痒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背颁褂。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工故响, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人颁独。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓彩届,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親誓酒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子樟蠕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容