更完整的 Android 拍照實(shí)現(xiàn)教程

咔嚓

簡(jiǎn)評(píng):官方文檔也可能會(huì)有不足窃肠,多踩坑包个,多分享。

作者在學(xué)習(xí) Google 官方的 Android 拍照教程 - Take Photos Simply 時(shí)冤留,遇到了一些問(wèn)題碧囊,感覺(jué)官方教程只寫了 90%树灶。為此,作者寫了這篇文章糯而,把完整的流程和一些要注意的地方都寫了下來(lái)天通,讓你不用再去查 StackOverflow 或者 Github Gist。

1.創(chuàng)建圖片文件

File imageFile; // use this to keep a reference to the file you create so that we can access it from onActivityResult()

private void createImageFile() throws IOException {
    String imageFileName = "image" + System.currentTimeMillis() + "_"; // give it a unique filename
    File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    // use this if you want android to automatically save it into the device's image gallery:
    // File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
    
    imageFile = File.createTempFile(imageFileName, ".jpg", storageDir);
}
  • 確保每個(gè)文件名都獨(dú)一無(wú)二熄驼,所以這里用到了 System.currentTimeMillis()像寒。
  • 注意代碼中注釋掉的那兩行,用它們會(huì)將拍的照片存放在手機(jī)相冊(cè)中瓜贾,在 Android 6.0 (API level 23) 以上诺祸,你需要?jiǎng)討B(tài)申請(qǐng)權(quán)限,可以考慮用 Permiso 庫(kù)來(lái)簡(jiǎn)化你的工作阐虚。

2.聲明權(quán)限

如果打算將照片存放在應(yīng)用的私有目錄中序臂,對(duì)于 Android 4.3 及以下的系統(tǒng)需要 WRITE_EXTERNAL_STORAGE 權(quán)限。

<manifest ...>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
                    android:maxSdkVersion="22" />
    
    <!--- If you want to save to the public image directory (the image gallery), you need to do this:
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    --->
    ...
</manifest>
  • 要求了 WRITE_EXTERNAL_STORAGE 權(quán)限的同時(shí)实束,也自然有了 READ_EXTERNAL_STORAGE 權(quán)限奥秆。
  • 如果是想把照片保存在手機(jī)相冊(cè)目錄下,所有版本的系統(tǒng)都需要 WRITE_EXTERNAL_STORAGE 權(quán)限咸灿。
  • 官方文檔中的 maxSdkVersion 為 18构订,可能會(huì)導(dǎo)致這個(gè)問(wèn)題:stackoverflow

3.配置 FileProvider

在 AndroidManifest.xml 中增加 FileProvider:

<application>
   ...
    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="{your.app.package}.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
      <meta-data
          android:name="android.support.FILE_PROVIDER_PATHS"
          android:resource="@xml/file_paths"/>
    </provider>
    ...
</application>
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
  <external-path name="external_files" path="."/>
</paths>

4.創(chuàng)建和開(kāi)始 Intent

當(dāng)創(chuàng)建 Intent 時(shí),判斷當(dāng)前設(shè)備是否有攝像頭并且能接受這個(gè) Intent避矢。此外悼瘾,需要額外添加 flag 來(lái)授權(quán)相機(jī)能寫入我們提供的文件。

public void startCameraIntent() {
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

    // Ensure that there's a camera activity to handle the intent
    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
      try {
        imageFile = createImageFile();
      } catch (IOException e) {
        // file wasn't created
      }

      if (imageFile != null) {
        Uri imageUri = FileProvider.getUriForFile(
            ExampleActivity.this,
            BuildConfig.APPLICATION_ID + ".fileprovider", 
            imageFile);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);

        // This is important. Without it, you may get Security Exceptions.
        // Google fails to mention this in their docs...
        // Taken from: https://github.com/commonsguy/cw-omnibus/blob/master/Camera/FileProvider/app/src/main/java/com/commonsware/android/camcon/MainActivity.java
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
          intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        }
        else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
          ClipData clip = ClipData.newUri(getContentResolver(), "A photo", imageUri);

          intent.setClipData(clip);
          intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        }
        else {
          List<ResolveInfo> resInfoList =
              getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);

          for (ResolveInfo resolveInfo : resInfoList) {
            String packageName = resolveInfo.activityInfo.packageName;
            grantUriPermission(packageName, imageUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
          }
        }
      }

      startActivityForResult(intent, REQUEST_CODE_CAMERA);
    }
    else {
      // device doesn't have camera
    }
  }
  • 注意其中的 BuildConfig.APPLICATION_ID + “.fileprovider” 是和 AndroidManifest.xml 中 provider 的 android:authorities 值一致的审胸。

5.獲取結(jié)果

@Override
 public void onActivityResult(int requestCode, int resultCode, Intent data) {  // note that data will be null  
    if (resultCode == Activity.RESULT_OK) {
      if (requestCode == REQUEST_CODE_CAMERA) {
        // imageFile will have the photo in it so do whatever you want with it
      }
    }
 }

原文:The Missing Documentation: Camera Intents

日?qǐng)?bào)延伸閱讀

歡迎關(guān)注

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末映企,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子静浴,更是在濱河造成了極大的恐慌堰氓,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件苹享,死亡現(xiàn)場(chǎng)離奇詭異双絮,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門掷邦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)白胀,“玉大人,你說(shuō)我怎么就攤上這事抚岗』蚋埽” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵宣蔚,是天一觀的道長(zhǎng)向抢。 經(jīng)常有香客問(wèn)我,道長(zhǎng)胚委,這世上最難降的妖魔是什么挟鸠? 我笑而不...
    開(kāi)封第一講書人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮亩冬,結(jié)果婚禮上艘希,老公的妹妹穿的比我還像新娘。我一直安慰自己硅急,他們只是感情好覆享,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著营袜,像睡著了一般撒顿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上荚板,一...
    開(kāi)封第一講書人閱讀 52,457評(píng)論 1 311
  • 那天凤壁,我揣著相機(jī)與錄音,去河邊找鬼跪另。 笑死拧抖,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的免绿。 我是一名探鬼主播徙鱼,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼针姿!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起厌衙,我...
    開(kāi)封第一講書人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤距淫,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后婶希,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體榕暇,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了彤枢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片狰晚。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖缴啡,靈堂內(nèi)的尸體忽然破棺而出壁晒,到底是詐尸還是另有隱情,我是刑警寧澤秒咐,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布碘裕,位于F島的核電站携取,受9級(jí)特大地震影響帮孔,放射性物質(zhì)發(fā)生泄漏雷滋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一文兢、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧禽作,春花似錦尸昧、人聲如沸旷偿。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)萍程。三九已至幢妄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蕉鸳,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工潮尝, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留饿序,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓原探,卻偏偏與公主長(zhǎng)得像顽素,于是被迫代替她去往敵國(guó)和親徒蟆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子胁出,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,306評(píng)論 25 707
  • ¥開(kāi)啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開(kāi)一個(gè)線程全蝶,因...
    小菜c閱讀 6,444評(píng)論 0 17
  • 只簡(jiǎn)述我發(fā)現(xiàn)問(wèn)題的根源戚哎,有些是適配了7.0,會(huì)報(bào)權(quán)限失敗問(wèn)題型凳,那是由于沒(méi)有動(dòng)態(tài)授權(quán)導(dǎo)致,接下來(lái)我一步一步給大家實(shí)現(xiàn)...
    Wocus閱讀 2,368評(píng)論 4 5
  • 帝都上周突然降溫埂蕊,降雨疏唾,實(shí)在是讓人不好接受... 本來(lái)上上周我都穿運(yùn)動(dòng)褲到處跑蓄氧,突然又得多穿些槐脏,而且坐在家里感覺(jué)跟...
    白跑磨鞋底閱讀 234評(píng)論 0 1
  • 昨夜 我發(fā)了一個(gè)很長(zhǎng)很長(zhǎng)的夢(mèng) 夢(mèng)里我有一匹棗棕色的大馬 在那還牽起一個(gè)半明半暗的她 還未趕早浪跡天涯 一回頭大馬跑...
    幸錦鈔閱讀 322評(píng)論 0 1