Android《第一行代碼》-調(diào)用攝像頭拍照問(wèn)題解決

說(shuō)明:由于在測(cè)試的時(shí)候使用的是Android 7.1的機(jī)器拧烦,所以郭霖大神書中的代碼會(huì)出現(xiàn)以下問(wèn)題虹曙,

(1)APP安裝在機(jī)器上實(shí)測(cè)會(huì)出現(xiàn)調(diào)用相機(jī)無(wú)法打開的現(xiàn)象;

(2)APP調(diào)用裁剪工具的時(shí)候會(huì)有Toast提示“無(wú)法加載此圖片”束莫。

以下是對(duì)郭霖大神在書中代碼的詳細(xì)講解以及適配唤锉,從而保證一切功能正常執(zhí)行。

Step 1. 新建一個(gè)activity_main.xml布局椅贱,這個(gè)沒(méi)什么問(wèn)題懂算。


android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical">

android:id="@+id/take_photo"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="拍照"/>

android:id="@+id/image_view"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center_horizontal"/>

Step 2. 新建MainActivity,以下是郭霖大神書中原來(lái)的代碼庇麦。代碼中比較難以理解的地方注釋都寫的很詳細(xì)计技。

public class MainActivity extends AppCompatActivity {
    public static final int TAKE_PHOTO = 1;
    public static final int CROP_PHOTO = 2;
    private Button takePhoto;
    private ImageView imageView;
    private Uri imageUri;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        takePhoto = (Button)findViewById(R.id.take_photo);
        imageView = (ImageView)findViewById(R.id.image_view);
        takePhoto.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                File outputImage = new File(Environment.getExternalStorageDirectory(),
                        "maybe.jpg");
                if(outputImage.exists()){
                    outputImage.delete();
                }
                try {
                    outputImage.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                //將File對(duì)象轉(zhuǎn)換成Uri對(duì)象,因?yàn)閁ri對(duì)象標(biāo)識(shí)著maybe.jpg這張圖片的唯一地址山橄。
                //由于Intent能傳遞的數(shù)據(jù)空間有限垮媒,所以需要轉(zhuǎn)化成Uri
                //大圖片用Uri,小圖片用Bitmap
                //以下代碼解決了Android 7.0 打開相機(jī)崩潰的問(wèn)題
                if(Build.VERSION.SDK_INT > 24){
                    imageUri = FileProvider.getUriForFile(MainActivity.this,
                            "com.example.android.choosepicdemo.fileprovider",outputImage);
                }else{
                    imageUri = Uri.fromFile(outputImage);
                }
                //Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);
                //第一個(gè)參數(shù):一個(gè)Intent對(duì)象
                //第二個(gè)參數(shù):如果> = 0,當(dāng)Activity結(jié)束時(shí)requestCode將歸還在onActivityResult()中,
                //以便確定返回的數(shù)據(jù)是從哪個(gè)Activity中返回
                startActivityForResult(intent,TAKE_PHOTO);
            }
        });
    }
    /*第一個(gè)參數(shù):這個(gè)整數(shù)requestCode提供給onActivityResult,是以便確認(rèn)返回的數(shù)據(jù)是從哪個(gè)Activity返回的驾胆。
            這個(gè)requestCode和startActivityForResult中的requestCode相對(duì)應(yīng)涣澡。
      第二個(gè)參數(shù):這整數(shù)resultCode是由子Activity通過(guò)其setResult()方法返回。
      第三個(gè)參數(shù):一個(gè)Intent對(duì)象丧诺,帶有返回的數(shù)據(jù)入桂。*/
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode){
            case TAKE_PHOTO:
                if(resultCode == RESULT_OK){
                    Intent intent = new Intent("com.android.camera.action.CROP");
                    //以下兩行代碼適配Android 7.0 解決了無(wú)法加載圖片的問(wèn)題
                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                    intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                    intent.setDataAndType(imageUri,"image/*");
                    intent.putExtra("scale",true);
                    intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);
                    startActivityForResult(intent,CROP_PHOTO);
                }
                break;
            case CROP_PHOTO:
                if(resultCode == RESULT_OK){
                    // 因?yàn)閕mageUri是Uri類型的,需要轉(zhuǎn)換才能被decodeStream使用
                    // 使用getContentResolver()
                    // 因?yàn)樵贏ndroid系統(tǒng)里面驳阎,數(shù)據(jù)庫(kù)是私有的抗愁。
                    // 一般情況下外部應(yīng)用程序是沒(méi)有權(quán)限讀取其他應(yīng)用程序的數(shù)據(jù)。
                    // 如果你想公開你自己的數(shù)據(jù)呵晚,你有兩個(gè)選擇:
                    // 你可以創(chuàng)建你自己的內(nèi)容提供器(一個(gè)ContentProvider子類)或者
                    // 你可以給已有的提供器添加數(shù)據(jù)-如果存在一個(gè)控制同樣類型數(shù)據(jù)的內(nèi)容提供器且你擁有寫的權(quán)限蜘腌。
                    // 外界的程序通過(guò)ContentResolver接口可以訪問(wèn)ContentProvider提供的數(shù)據(jù),
                    // 在Activity當(dāng)中通過(guò)getContentResolver()可以得到當(dāng)前應(yīng)用的 ContentResolver實(shí)例
                    try {
                        //解析成Bitmap
                        Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
                        imageView.setImageBitmap(bitmap);
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    }
                }
                break;
            default:
                break;
        }
    }
}

需要注意的是以下代碼是增加了的內(nèi)容:

               //以下代碼解決了Android 7.0 打開相機(jī)崩潰的問(wèn)題
                if(Build.VERSION.SDK_INT > 24){
                    imageUri = FileProvider.getUriForFile(MainActivity.this,
                            "com.example.android.choosepicdemo.fileprovider",outputImage);
                }else{
                    imageUri = Uri.fromFile(outputImage);
                }

如果不這么處理的話饵隙,會(huì)導(dǎo)致在調(diào)用相機(jī)獲取 Uri 的時(shí)候發(fā)生崩潰撮珠。

原因很明顯,file:// 不被允許作為一個(gè)附加的 Uri 的意圖金矛,否則會(huì)拋出 FileUriExposedException 芯急。其實(shí)背后有一個(gè)很好的理由勺届,如果文件路徑被發(fā)送到目標(biāo)應(yīng)用程序(相機(jī)應(yīng)用程序在這種情況下),文件將完全訪問(wèn)通過(guò)相機(jī)應(yīng)用程序的過(guò)程娶耍,而不僅僅只有發(fā)起者能收到免姿。但讓我們考慮一下,實(shí)際上是由我們的應(yīng)用程序去啟動(dòng)攝像頭拍照榕酒,并保存作為我們的應(yīng)用程序的代表文件胚膊。因此,該文件的訪問(wèn)權(quán)限應(yīng)該是我們的應(yīng)用程序而不是攝像頭應(yīng)用程序本身想鹰。這就是為什么現(xiàn)在 file:// 在 targetSdkVersion 24 中要求每一位開發(fā)者都去完成這個(gè)任務(wù)紊婉。參考博文:http://www.sohu.com/a/136282885_659256

所以需要采用FileProvider來(lái)處理。
具體的步驟如下:

  • 首先在AndroidManifest.xml中聲明provider杖挣。這里要注意android:authorities要是你的包名一致肩榕,其他固定。
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <provider
            android:authorities="com.example.android.choosepicdemo.fileprovider"
            android:name="android.support.v4.content.FileProvider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
        </provider>
    </application>

</manifest>
  • 在res文件夾下創(chuàng)建xml文件夾惩妇,并創(chuàng)建provide_paths.xml(該名稱應(yīng)與上述android:resource里一致),maybe為圖片保存時(shí)的名稱株汉,根據(jù)你自己命名而定。
<?xml version="1.0" encoding="utf-8"?>
    <paths xmlns:android="http://schemas.android.com/apk/res/android">
        <external-path name = "maybe" path = "."/>
    </paths>
  • 修改java代碼如下
               //以下代碼解決了Android 7.0 打開相機(jī)崩潰的問(wèn)題
                if(Build.VERSION.SDK_INT > 24){
                    imageUri = FileProvider.getUriForFile(MainActivity.this,
                            "com.example.android.choosepicdemo.fileprovider",outputImage);
                }else{
                    imageUri = Uri.fromFile(outputImage);
                }

到這里就解決了在android 7.0以上平臺(tái)上調(diào)用攝像頭崩潰的問(wèn)題歌殃。
Step 3. 解決調(diào)用裁剪工具時(shí)提示“無(wú)法加載圖片”的問(wèn)題
很簡(jiǎn)單乔妈,在MainActivity.java中加上兩行代碼就搞定。

//以下兩行代碼適配Android 7.0 解決了無(wú)法加載圖片的問(wèn)題
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

以上氓皱。
點(diǎn)擊此處下載源碼路召。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市波材,隨后出現(xiàn)的幾起案子股淡,更是在濱河造成了極大的恐慌,老刑警劉巖廷区,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件唯灵,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡隙轻,警方通過(guò)查閱死者的電腦和手機(jī)埠帕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)玖绿,“玉大人敛瓷,你說(shuō)我怎么就攤上這事“叻耍” “怎么了呐籽?”我有些...
    開封第一講書人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我绝淡,道長(zhǎng)宙刘,這世上最難降的妖魔是什么苍姜? 我笑而不...
    開封第一講書人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任牢酵,我火速辦了婚禮,結(jié)果婚禮上衙猪,老公的妹妹穿的比我還像新娘馍乙。我一直安慰自己,他們只是感情好垫释,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開白布丝格。 她就那樣靜靜地躺著,像睡著了一般棵譬。 火紅的嫁衣襯著肌膚如雪显蝌。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,718評(píng)論 1 305
  • 那天订咸,我揣著相機(jī)與錄音曼尊,去河邊找鬼。 笑死脏嚷,一個(gè)胖子當(dāng)著我的面吹牛骆撇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播父叙,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼神郊,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了趾唱?” 一聲冷哼從身側(cè)響起涌乳,我...
    開封第一講書人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎甜癞,沒(méi)想到半個(gè)月后夕晓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡带欢,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年运授,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乔煞。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡吁朦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出渡贾,到底是詐尸還是另有隱情逗宜,我是刑警寧澤,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站纺讲,受9級(jí)特大地震影響擂仍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜熬甚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一逢渔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧乡括,春花似錦肃廓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至敷扫,卻和暖如春哀蘑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背葵第。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工绘迁, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人羹幸。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓脊髓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親栅受。 傳聞我的和親對(duì)象是個(gè)殘疾皇子将硝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,182評(píng)論 25 707
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)屏镊,斷路器依疼,智...
    卡卡羅2017閱讀 134,667評(píng)論 18 139
  • 在前面一篇文章中律罢,我們分析了Android應(yīng)用程序窗口的繪圖表面的創(chuàng)建過(guò)程。Android應(yīng)用程序窗口的繪圖表面在...
    一個(gè)不掉頭發(fā)的開發(fā)閱讀 4,578評(píng)論 0 14
  • 這夜棍丐,真是太靜了误辑,只聽得見(jiàn)院墻外柴垛老鼠扭捏的稀疏聲,屯里誰(shuí)家的幾聲犬吠歌逢,極遠(yuǎn)處傳來(lái)的煙花聲巾钉,尋去那處也忘不到綻放...
    夢(mèng)玉芷閱讀 284評(píng)論 0 0
  • 工作總結(jié): 1、今天做2017年(7)湖南卷秘案。題目偏南砰苍,不是那種簡(jiǎn)單直入潦匈,還是需要拐個(gè)小彎的。 2赚导、四點(diǎn)五十開會(huì)茬缩,...
    放牛的小孩閱讀 244評(píng)論 0 0