Android調(diào)用系統(tǒng)相機(jī)、相冊周崭、剪裁圖片并上傳(常用于上傳頭像喳张,兼容Android7.0)

前言

在我們的日常開發(fā)當(dāng)中,調(diào)用相機(jī)和從相冊中選擇照片裁剪并上傳是很常見的功能,網(wǎng)上有很多框架,但是導(dǎo)入別人的庫, 無疑增加了App的體積,因此這里講一下如何使用系統(tǒng)自帶的相機(jī),相冊,并裁剪,個人感覺還行

第一步 : FileProvider準(zhǔn)備相關(guān)

  1. 在AndroidManifest.xml中增加provider節(jié)點(diǎn)蹲姐,如下:
<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.dream.takephotodemo"
    android:grantUriPermissions="true"
    android:exported="false">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/filepaths" />
</provider>

其中: android:authorities 表示授權(quán)列表,填寫你的應(yīng)用包名忙厌,當(dāng)有多個授權(quán)時江咳,用分號隔開 android:exported 表示該內(nèi)容提供器(ContentProvider)是否能被第三方程序組件使用,必須為false爹土,否則會報異常:ava.lang.RuntimeException: Unable to get provider android.support.v4.content.FileProvider: java.lang.SecurityException: Provider must not be exported android:grantUriPermissions="true" 表示授予 URI 臨時訪問權(quán)限 android:resource 屬性指向我們自及創(chuàng)建的xml文件的路徑,文件名隨便起

  1. 接下來社露,我們需要在資源(res)目錄下創(chuàng)建一個xml目錄琼娘,并建立一個以上面名字為文件名的xml文件,內(nèi)容如下:

     <?xml version="1.0" encoding="utf-8"?>
    <paths>
       <external-path path="." name="external_path" />
    </paths>
    

其中: external-path 代表根目錄為: Environment.getExternalStorageDirectory() 瞒瘸,也可以寫其他的熄浓,如: files-path 代表根目錄為:Context.getFilesDir() cache-path 代表根目錄為:getCacheDir() 其path屬性的值代表路徑后層級名稱,為空則代表就是根目錄俯在,假如為“pictures”,就代表對應(yīng)根目錄下的pictures目錄

第二步:使用FileProvider

  • 在這之前惯雳,我們需要在AndroidManifest.xml中增加必要的讀寫權(quán)限:

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

1. 通過相機(jī)獲取圖片

/**
 * 拍照
 */ 
private void takePhoto() {
    //用于保存調(diào)用相機(jī)拍照后所生成的文件
    if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
        return;
    }
    captureFile = new File(rootFile, "temp.jpg");
    //跳轉(zhuǎn)到調(diào)用系統(tǒng)相機(jī)
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    //判斷版本 如果在Android7.0以上,使用FileProvider獲取Uri
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        intent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        Uri contentUri = FileProvider.getUriForFile(mContext, getPackageName(), captureFile);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);
    } else {
        //否則使用Uri.fromFile(file)方法獲取Uri
        intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(captureFile));
    }
    startActivityForResult(intent, REQUEST_PERMISSION_CAMERA);
}

2. 通過相冊獲取圖片

 /**
 * 從相冊選擇
 */
private void choosePhoto() {
    Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
    photoPickerIntent.setType("image/*");
    startActivityForResult(photoPickerIntent, REQUEST_PERMISSION_WRITE);
}

3. 圖片裁剪

  /**
 * 裁剪圖片
 */
private void cropPhoto(Uri uri) {
    cropFile = new File(rootFile, "avatar.jpg");
    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", 300);
    intent.putExtra("outputY", 300);
    intent.putExtra("return-data", false);//注意這里返回false,因?yàn)樵诓糠质謾C(jī)上獲取不到返回的數(shù)據(jù)
    intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(cropFile));
    intent.putExtra("outputFormat", Bitmap.CompressFormat.PNG.toString());
    intent.putExtra("noFaceDetection", true);
    intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    startActivityForResult(intent, CROP_REQUEST_CODE);
}

第三步:接收圖片信息

  • 我們在onActivityResult方法中獲得返回的圖片信息,在這里我們會先調(diào)用剪裁去剪裁圖片,然后對剪裁返回的圖片進(jìn)行設(shè)置、保存拙吉、上傳等操作

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
      if (resultCode == RESULT_OK) {
          switch (requestCode) {
              case REQUEST_PERMISSION_CAMERA:
                  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                      Uri contentUri = FileProvider.getUriForFile(mContext, getPackageName(), captureFile);
                      cropPhoto(contentUri);
                  } else {
                      cropPhoto(Uri.fromFile(captureFile));
                  }
                  break;
              case REQUEST_PERMISSION_WRITE:
                  cropPhoto(data.getData());
                  break;
              case CROP_REQUEST_CODE:
                  saveImage(cropFile.getAbsolutePath());
                  ivAvatar.setImageBitmap(BitmapFactory.decodeFile(cropFile.getAbsolutePath()));
                  break;
              default:
                  break;
          }
      }
      super.onActivityResult(requestCode, resultCode, data);
    }
    
  • 保存圖片到本地

    public String saveImage(String path) {
      if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
          return null;
      }
      Bitmap bitmap = BitmapFactory.decodeFile(path);
      try {
          FileOutputStream fos = new FileOutputStream(cropFile);
          bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
          fos.flush();
          fos.close();
          return cropFile.getAbsolutePath();
      } catch (IOException e) {
          e.printStackTrace();
      }
      return null;
    }
    

至此筷黔,對Android7.0的兼容就結(jié)束了佛舱,注意在調(diào)用相機(jī)和裁剪時,傳入的Uri需要使用FileProvider來獲取

總結(jié)

拍照或從相冊中選取時,我們首先要判斷是否有拍照或讀寫SD卡的權(quán)限,如果沒有則需要動態(tài)申請權(quán)限,這里我用的一個第三方庫傳送門,有了權(quán)限之后在進(jìn)行下一步操作,還需要注意判斷當(dāng)前SD卡是否可用,做了這些判斷之后,相信調(diào)用系統(tǒng)的拍照或者從相冊中選擇將會變得很簡單

最后附上Demo地址傳送門

如果大家對我的文章感興趣的話,請為我點(diǎn)贊,謝謝!!!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末订歪,一起剝皮案震驚了整個濱河市肆捕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌眼虱,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件撞蚕,死亡現(xiàn)場離奇詭異过牙,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)矫渔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門庙洼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來镊辕,“玉大人,你說我怎么就攤上這事征懈。” “怎么了鬼悠?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵亏娜,是天一觀的道長维贺。 經(jīng)常有香客問我,道長溯泣,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任客给,我火速辦了婚禮栏尚,結(jié)果婚禮上只恨,老公的妹妹穿的比我還像新娘抬虽。我一直安慰自己,他們只是感情好休涤,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布功氨。 她就那樣靜靜地躺著手幢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪围来。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天桶错,我揣著相機(jī)與錄音院刁,去河邊找鬼粪狼。 笑死,一個胖子當(dāng)著我的面吹牛鸳玩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼窝革,長吁一口氣:“原來是場噩夢啊……” “哼吕座!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起漆诽,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎兰英,沒想到半個月后供鸠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡薄坏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年胶坠,在試婚紗的時候發(fā)現(xiàn)自己被綠了繁堡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片涵但。...
    茶點(diǎn)故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡矮瘟,死狀恐怖塑娇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情哨啃,我是刑警寧澤写妥,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站祝峻,受9級特大地震影響扎筒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜嗜桌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一骨宠、第九天 我趴在偏房一處隱蔽的房頂上張望相满。 院中可真熱鬧桦卒,春花似錦、人聲如沸闸盔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽击费。三九已至,卻和暖如春谆棱,著一層夾襖步出監(jiān)牢的瞬間圆仔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工个从, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留歪沃,地道東北人。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓奕污,卻偏偏與公主長得像液走,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子腻窒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評論 2 345

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