Android調(diào)用系統(tǒng)相機(jī)得院、圖庫(kù)、裁剪圖片并壓縮上傳(適配7.0)

一章贞、前言

最近在開發(fā)中遇到了一個(gè)比較棘手的問題
由于在之前使用的版本-targetSdkVersion小于24也就是小于7.0所以在使用相機(jī)拍照的時(shí)候不會(huì)出現(xiàn)問題祥绞,但是當(dāng)targetSdkVersion版本大于或者等于7.0的時(shí)候用原來(lái)的方法調(diào)用相機(jī)就會(huì)拋出一個(gè)SecurityException安全異常

通過搜索發(fā)現(xiàn)是出于對(duì)系統(tǒng)安全的考慮,在sdk24及以上鸭限,對(duì)相機(jī)的操作需要使用FileProvider才行蜕径。
雖然有些麻煩,但除非用第三方框架败京,不然也只能自己動(dòng)手去解決了兜喻。

二、操作流程

image.png

1赡麦、定義全局標(biāo)識(shí)

用于接收?qǐng)D庫(kù)選擇或拍照完成后的結(jié)果回調(diào)

    //圖庫(kù)
    private static final int PHOTO_TK = 0;
    //拍照
    private static final int PHOTO_PZ = 1;
    //裁剪
    private static final int PHOTO_CLIP = 2;

定義全局的uri

private Uri contentUri;

2朴皆、圖庫(kù)操作

這里用的是一個(gè)自定義的dialog


update_dialog_TK.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //調(diào)用系統(tǒng)圖庫(kù),選擇圖片
                Intent intent = new Intent(Intent.ACTION_PICK, null);
                intent.setDataAndType(
                        MediaStore.Images.Media.INTERNAL_CONTENT_URI, "image/*");
                //返回結(jié)果和標(biāo)識(shí)
                startActivityForResult(intent, PHOTO_TK);
                dialog.dismiss();
            }
        });

3泛粹、相機(jī)操作

3.1 Android7.0以下版本

直接調(diào)用系統(tǒng)相機(jī)遂铡,通過日志可以看到會(huì)返回一個(gè)類似
file:///storage/emulated/0/temp.jpg的文件

update_dialog_PZ.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 啟動(dòng)系統(tǒng)相機(jī)
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                // 獲取拍完后的uri
                Uri mImageCaptureUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(), "temp.jpg"));
                intent.putExtra(MediaStore.EXTRA_OUTPUT, mImageCaptureUri);
                //  返回結(jié)果和標(biāo)識(shí)
                startActivityForResult(intent, PHOTO_PZ);
                dialog.dismiss();
            }
        });
3.2 兼容Android7.0以上版本

在新的版本中,Android對(duì)內(nèi)容提供者做了限制晶姊,返回的不再是uri扒接,而需要一個(gè)FileProvider
使用 content://代替了 file:///
所以如果直接使用原來(lái)的方法就會(huì)報(bào)錯(cuò)。
所以在之前我們要給AndroidManifest文件中application標(biāo)簽添加權(quán)限

<provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="你的包名.fileProvider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths" />
        </provider>

并且需要?jiǎng)?chuàng)建一個(gè)xml
(可以在上面android:resource="@xml/provider_paths"直接使用快捷鍵alt+enter創(chuàng)建们衙,然后將代碼拷貝進(jìn)去)
external-path標(biāo)簽用來(lái)指定Uri共享钾怔,name屬性的值可以自定義,path屬性的值表示共享的具體位置

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>

然后在調(diào)用系統(tǒng)相機(jī)的時(shí)候判斷

update_dialog_PZ.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 啟動(dòng)系統(tǒng)相機(jī)
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                Uri mImageCaptureUri;
                // 判斷7.0android系統(tǒng)
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    //臨時(shí)添加一個(gè)拍照權(quán)限
                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                    //通過FileProvider獲取uri
                    contentUri = FileProvider.getUriForFile(UpdatePhotoActivity.this,
                            "你的包名.fileProvider",
                            new File(Environment.getExternalStorageDirectory(), "temp.jpg"));
                    intent.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);
                } else {
                    mImageCaptureUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(), "temp.jpg"));
                    intent.putExtra(MediaStore.EXTRA_OUTPUT, mImageCaptureUri);
                }
                startActivityForResult(intent, PHOTO_PZ);
                dialog.dismiss();
            }
        });

4蒙挑、 onActivityResult

使用onActivityResult接收操作完成的回調(diào)

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK) {
            switch (requestCode) {
                case PHOTO_PZ:
                  //獲取拍照結(jié)果蒂教,執(zhí)行裁剪
                   Uri pictur;
                  //如果是7.0android系統(tǒng),直接獲取uri
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        pictur = contentUri;
                    } else {
                        pictur = Uri.fromFile(new File(
                                Environment.getExternalStorageDirectory() + "/temp.jpg"));
                    }
                    startPhotoZoom(pictur);
                    break;
                case PHOTO_TK:
                    //獲取圖庫(kù)結(jié)果脆荷,執(zhí)行裁剪
                    startPhotoZoom(data.getData());
                    break;  
                case PHOTO_CLIP:
                    //裁剪完成后的操作凝垛,上傳至服務(wù)器或者本地設(shè)置
                    break;
            }
        }
    }

5懊悯、裁剪

當(dāng)拍照完成后或者本地選擇圖片完畢之后會(huì)執(zhí)行該方法。同時(shí)也做了7.0適配

  /**
     * 裁剪圖片的方法.
     * 用于拍照完成或者選擇本地圖片之后
     */
    private Uri uritempFile;

    public void startPhotoZoom(Uri uri) {
        Log.e("uri=====", "" + uri);
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(uri, "image/*");
        intent.putExtra("crop", "true");
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        intent.putExtra("outputX", 60);
        intent.putExtra("outputY", 60);
        //uritempFile為Uri類變量梦皮,實(shí)例化uritempFile
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            //開啟臨時(shí)權(quán)限
            intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
            //重點(diǎn):針對(duì)7.0以上的操作
            intent.setClipData(ClipData.newRawUri(MediaStore.EXTRA_OUTPUT, uri));
            uritempFile = uri;
        } else {
            uritempFile = Uri.parse("file://" + "/" + Environment.getExternalStorageDirectory().getPath() + "/" + "small.jpg");
        }
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uritempFile);
        intent.putExtra("return-data", false);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        intent.putExtra("noFaceDetection", true);
        startActivityForResult(intent, PHOTO_CLIP);
    }

三炭分、裁剪后的處理

在onActivityResult方法還有一個(gè)最后的處理,前面只是在給圖片做操作剑肯,下面是將完成后的圖片選擇加載到本地或者上傳到項(xiàng)目的服務(wù)端捧毛,一般在實(shí)際開發(fā)中用的比較多

1、加載至本地

使用Picasso加載让网,因?yàn)镻icasso支持Uri呀忧、File、Stirng類型溃睹,不需要做進(jìn)一步的轉(zhuǎn)換就可以直接用而账。

Picasso.with(this)
                 .load(uritempFile)
                 .into(cardviewImg);

2、轉(zhuǎn)成File并壓縮因篇、上傳

在實(shí)際開發(fā)中有時(shí)候需要對(duì)圖片進(jìn)行進(jìn)一步的處理泞辐,比如傳到服務(wù)器需要File類型的文件,所以就需要進(jìn)行再一次的轉(zhuǎn)換竞滓。
具體可以根據(jù)需求來(lái)進(jìn)行相應(yīng)的操作


                        //裁剪后的圖像轉(zhuǎn)成BitMap
                        photo1 = BitmapFactory.decodeStream(getContentResolver().openInputStream(uritempFile));
                        //創(chuàng)建路徑
                        String path = Environment.getExternalStorageDirectory()
                                .getPath() + "/Pic";
                        //獲取外部?jī)?chǔ)存目錄
                        file = new File(path);
                        Log.e("file", file.getPath());
                        //創(chuàng)建新目錄
                        file.mkdirs();
                        //以當(dāng)前時(shí)間重新命名文件
                        long i = System.currentTimeMillis();
                        //生成新的文件
                        file = new File(file.toString() + "/" + i + ".png");
                        Log.e("fileNew", file.getPath());
                        //創(chuàng)建輸出流
                        OutputStream out = new FileOutputStream(file.getPath());
                        //壓縮文件咐吼,返回結(jié)果
                        boolean flag = photo1.compress(Bitmap.CompressFormat.JPEG, 100, out);

項(xiàng)目demo地址:https://github.com/wapchief/android-CollectionDemo


相關(guān)文章:
Android版本相機(jī)適配問題集合(不斷整理更新中)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市商佑,隨后出現(xiàn)的幾起案子锯茄,更是在濱河造成了極大的恐慌,老刑警劉巖茶没,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件撇吞,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡礁叔,警方通過查閱死者的電腦和手機(jī)牍颈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)琅关,“玉大人煮岁,你說我怎么就攤上這事』烈祝” “怎么了画机?”我有些...
    開封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)新症。 經(jīng)常有香客問我步氏,道長(zhǎng),這世上最難降的妖魔是什么徒爹? 我笑而不...
    開封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任荚醒,我火速辦了婚禮芋类,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘界阁。我一直安慰自己侯繁,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開白布泡躯。 她就那樣靜靜地躺著贮竟,像睡著了一般。 火紅的嫁衣襯著肌膚如雪较剃。 梳的紋絲不亂的頭發(fā)上咕别,一...
    開封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音写穴,去河邊找鬼惰拱。 笑死,一個(gè)胖子當(dāng)著我的面吹牛确垫,可吹牛的內(nèi)容都是我干的弓颈。 我是一名探鬼主播帽芽,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼删掀,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了导街?” 一聲冷哼從身側(cè)響起披泪,我...
    開封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎搬瑰,沒想到半個(gè)月后款票,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡泽论,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年艾少,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片翼悴。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡缚够,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鹦赎,到底是詐尸還是另有隱情谍椅,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布古话,位于F島的核電站雏吭,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏陪踩。R本人自食惡果不足惜杖们,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一悉抵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧胀莹,春花似錦基跑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至荆秦,卻和暖如春篱竭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背步绸。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工掺逼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人瓤介。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓吕喘,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親刑桑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子氯质,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

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