拍照或從相冊選擇圖片是我們日常開發中經常使用到的,可以說是必須掌握的東西。上一篇我介紹了如何生成自定義二維碼《Android生成自定義二維碼》,其中logo和代替黑色色塊的圖片都是寫死的,所以現在我們就來實現拍照或者從相冊選取圖片這個功能。

先看效果圖:

拍照

1.啟動相機程序

拍照可以直接啟動系統的相機程序,代碼如下

Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); startActivityForResult(intent, TAKE_PHOTO);

這里我們利用一個隱式Intent來啟動相機程序,其中action類型:android.media.action.IMAGE_CAPTURE 表示啟動相機應用並請求一張圖片。創建了Intent對象,還需指定圖片的保存路徑,調用Intent的putExtra()方法並傳入保存路徑即可,最后調用startActivityForResult啟動活動,重寫onActivityResult()方法就能得到返回值。

2.指定保存路徑

上面的intent中指定了保存路徑,也就是代碼中的imageUri。首先需要創建一個File對象用來存放圖片,並使用getExternalCacheDir()方法將圖片放入SD卡當前應用包名下的緩存目錄中。

接着需要將File對象轉換成Uri對象,需要進行版本判斷,7.0以下直接調用Uri的fromFile方法,得到的是圖片本地真實路徑。7.0以上直接使用真實路徑會被認為不安全,會拋出異常,所以需要使用特殊的內容提供器FileProvider,它是ContentProvider的一個子類,作用便是將受限的Uri轉換為可共享的Uri。

既然使用內容提供器,當然需要進行注冊了,AndroidManifest.xml中加入:

meta-data標簽中的內容是用來添加一個共享目錄的,引用了一個resource資源,所以需要在 res/xml 目錄下新建這個 xml 文件,用於存放應用需要共享的目錄文件。

接下來在代碼中調用FileProvider的getUriForFile()方法生成Uri對象,需要傳入三個參數,第一個參數是上下文,第二個參數便是 Manifest 文件中注冊 FileProvider 時設置的 authorities 屬性值,第三個參數為要共享的文件,也就是之前創建的File對象。

完整代碼

/*** 拍照*/

private voidtakePhoto() {//創建File對象,用於存儲拍照后的圖片

File outputImage = new File(getExternalCacheDir(), "output_image.jpg");try{if(outputImage.exists()) { outputImage.delete(); } outputImage.createNewFile(); }catch(IOException e) { e.printStackTrace(); }if (Build.VERSION.SDK_INT < 24) { imageUri=Uri.fromFile(outputImage); }else{ imageUri= FileProvider.getUriForFile(MainActivity.this, "com.example.xch.generateqrcode.fileprovider", outputImage); }//啟動相機程序

Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); startActivityForResult(intent, TAKE_PHOTO); }

獲取拍照結果:

@Overrideprotected void onActivityResult(int requestCode, intresultCode, Intent data) {switch(requestCode) {caseTAKE_PHOTO:if (resultCode ==RESULT_OK) {try{//讀取拍照結果

logoBitmap =BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri)); }catch(Exception e) { e.printStackTrace(); } }break;default:break; } }

讀取拍照結果利用ContentResolver的openInputStream()方法,並傳入剛才圖片的保存路徑即可獲取圖片字節流,再利用BitmapFactory的decodeStream()方法轉為Bitmap格式,如果擔心OOM,可先進行壓縮。

最后別忘了在AndroidManifest.xml中加入權限

從相冊選擇圖片

打開相冊

同樣用Intent,action類型為android.intent.action.GET_CONTENT ,並給intent設置type為圖片,如下:

Intent intent = new Intent("android.intent.action.GET_CONTENT"); intent.setType("image/*"); startActivityForResult(intent, CHOOSE_PHOTO);

獲取結果

在回調onActivityResult即可對返回結果進行處理

@Overrideprotected void onActivityResult(int requestCode, intresultCode, Intent data) {switch(requestCode) {caseCHOOSE_PHOTO:if (resultCode ==RESULT_OK) {//判斷手機系統版本號

if (Build.VERSION.SDK_INT >= 19) {//4.4及以上系統使用這個方法處理圖片

handleImageOnKitKat(data); }else{//4.4以下系統使用這個方法處理圖片

handleImageBeforeKitKat(data); } }break;default:break; } }

由於Android 4.4開始,不再返回圖片真實的Uri,而是一個封裝過的Uri,因此需要分別進行處理。Android 4.4之前直接調用getImagePath()方法通過Uri和selection就可獲取真實路徑,如下

/*** 4.4版本以前,直接獲取真實路徑 *@paramdata*/

private voidhandleImageBeforeKitKat(Intent data) { Uri uri=data.getData(); String imagePath= getImagePath(uri, null);//顯示圖片

displayImage(imagePath); }privateString getImagePath(Uri uri, String selection) { String path= null;//通過Uri和selection來獲取真實的圖片路徑

Cursor cursor = getContentResolver().query(uri, null, selection, null, null);if (cursor != null) {if(cursor.moveToFirst()) { path=cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); } cursor.close(); }returnpath; }

Android 4.4之后,需要解析封裝過的Uri,如果Uri是document類型,則通過document id處理,如果是content類型的Uri,則使用普通方式處理,如果是file類型的Uri,直接獲取圖片路徑即可。獲取到路徑后即可顯示,如下

private voidhandleImageOnKitKat(Intent data) { String imagePath= null; Uri uri=data.getData();if (DocumentsContract.isDocumentUri(this, uri)) {//如果是document類型的Uri,則通過document id處理

String docId =DocumentsContract.getDocumentId(uri);if ("com.android.providers.media.documents".equals(uri.getAuthority())) { String id= docId.split(":")[1]; //解析出數字格式的id

String selection = MediaStore.Images.Media._ID + "=" +id; imagePath=getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection); }else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) { Uri contentUri= ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId)); imagePath= getImagePath(contentUri, null); } }else if ("content".equalsIgnoreCase(uri.getScheme())) {//如果是content類型的Uri,則使用普通方式處理

imagePath = getImagePath(uri, null); }else if ("file".equalsIgnoreCase(uri.getScheme())) {//如果是file類型的Uri,直接獲取圖片路徑即可

imagePath =uri.getPath(); } displayImage(imagePath);//根據圖片路徑顯示圖片

}

顯示圖片

/*** 顯示圖片 *@paramimagePath 圖片路徑*/

private voiddisplayImage(String imagePath) {if (imagePath != null) { logoBitmap=BitmapFactory.decodeFile(imagePath);//顯示圖片

picture_logo.setImageBitmap(logoBitmap); }else{ Toast.makeText(this, "獲取圖片失敗", Toast.LENGTH_SHORT).show(); } }

動態權限申請

由於涉及了敏感權限 WRITE_EXTERNAL_STORAGE ,所以需要進行權限的動態申請,如下

//動態權限申請

if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) !=PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1); }else{//打開相冊

openAlbum(); }

@Overridepublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {switch(requestCode) {case 1:if (grantResults.length > 0 && grantResults[0] ==PackageManager.PERMISSION_GRANTED) {//打開相冊

openAlbum(); }else{ Toast.makeText(this, "你拒絕了權限申請,可能無法打開相冊喲", Toast.LENGTH_SHORT).show(); }break;default: } }

上面的代碼就是動態申請權限的流程,首先判斷用戶是不是已經給我們權限授權了,使用ContextCompat.checkSelfPermission()方法,第一個參數是Context,第二個參數是具體的權限名稱,如果等於PackageManager.PERMISSION_GRANTED表明已授權,不等於就是沒有授權。

如果已授權就直接做后面的操作,如果沒有授權,需要調用ActivityCompat.requestPermissions()方法申請授權,第一個參數是當前Activity實例,第二個參數是權限數組,第三個是請求碼。

用戶的選擇將會回調到onRequestPermissionsResult()方法中,授權結果封裝在grantResults參數中,如果被授權,則打開相冊,否則提示用戶未打開權限無法使用。

android 拍照无法生成图片,Android生成二維碼--拍照或從相冊選取圖片相关推荐

  1. Android二維碼掃描

    总是站在牛人的肩膀上在~~ 直接上代码了 添加Gradle依赖:(其实都是人家的...) compile 'com.google.zxing:core:3.1.0' compile 'cn.bingo ...

  2. android高仿微信拍照、多选、预览、删除(去除相片)相冊功能

    先声明授人与鱼不如授人与渔,仅仅能提供一个思路,当然须要源代码的同学能够私下有偿问我要源代码:QQ:508181017 工作了将近三年时间了,一直没正儿八经的研究系统自带的相冊和拍照,这回来个高仿微信 ...

  3. c#生成图片、生成二维码、读取excel、自动匹配路径

    以下是个园林树牌信息生成程序,是使用c#语言编写的控制台程序,包含了生成图片.生成二维码.读取excel.自动匹配路径等功能,可作为以上功能的demo.注意只有系统中已有的字体才可以使用,如果使用系统 ...

  4. Android生成二维码--拍照或从相册选取图片

    拍照或从相册选择图片是我们日常开发中经常使用到的,可以说是必须掌握的东西.上一篇我介绍了如何生成自定义二维码<Android生成自定义二维码>,其中logo和代替黑色色块的图片都是写死的, ...

  5. Android扫一扫和生成二维码(使用华为ScanKit)

    本文主要讲如何使用华为统一扫码scan Kit进行扫一扫以及生成二维码, 有兴趣的可以看一下华为扫描和Zxing扫描的区别 使用步骤 1.在全局的build.gradle文件里添加华为maven仓库 ...

  6. Android开发规范,flutter生成二维码

    变量命名要做到足够长有一定意义,同时又足够短以避免冗长. 关于携带Android控件的变量,个人建议规则:[控件逻辑名称]+[控件缩写] 如mLoginBtn, mBottomLayout, mTit ...

  7. android zxing 集成过程,android 集成Zxing教程

    關於Zxing集成教程,網上有很多很多,我想說你妹的很多都是"copy,copy,copy",問題是尼瑪到最后還出不來...前幾天看了android Bus網站,看到了一個集成Zx ...

  8. android 解析、生成二维码

    android 解析.生成二维码 (1)ZXing是一个开源Java类库用于解析多种格式的1D/2D条形码.目标是能够对QR编码.Data Matrix.UPC的1D条形码进行解码. 其提供了多种平台 ...

  9. PHP基于phpqrcode类生成二维码

    使用ThinkPHP框架引入phpqrcode类生成二维码后,发现每次必须通过TP框架生成,略显繁琐,打算写一个简单的方法,然后运行php后直接批量生成二维码.方法也简单,直接写个PHP脚本,然后引入 ...

最新文章

  1. SQLserver安全设置攻略
  2. mysql 分库分表,真的能支持服务无限扩容么?
  3. 英国EE:启动TechCity 2.0 首期将部署LTE-Advanced Pro
  4. 二叉树 跳表_漫谈 LevelDB 数据结构(一):跳表(Skip List)
  5. [数据结构]顺序单链表插入
  6. 突破边界局限,阿里云神龙负责人张献涛分享15年虚拟化之路
  7. Qt安装事件过滤器、过滤子控件事件、截获控件按键、鼠标事件
  8. 将vim打造成python开发工具
  9. QGIS 3.0 使用教程
  10. matlab dll 通达信,通达信DLL插件实战篇,怎样制作我们想要的函数
  11. java正态分布随机数产生方法
  12. [日语]学习“五十音”(读音篇)
  13. visual studio进入时许可证已过期解决方案
  14. HDU 4602 Partition 规律题
  15. 【远程连接】SSH链接远程主机
  16. HTML CSS 学习总结
  17. 【sdx62】WCN6856加载wlan.ko系统崩溃问题解决方案
  18. 夜来风雨声,对象知多少。
  19. 相机显示无法访问内存卡?看完你就明白了
  20. vue使用windows自带能力播放音频

热门文章

  1. Matlab车牌识别停车场车辆进出管理系统
  2. numpy.eye()函数简单使用
  3. android通知 自动消失了,为什么通知会在android通知栏中显示一段时间然后消失
  4. 情感计算-基于肢体动作和生理信号的情感识别
  5. 抗渗等级p6是什么意思_混凝土p6是什么意思
  6. 有赞电商云应用框架设计
  7. Elasticsearch从入门到放弃:人生若只如初见
  8. 周志华团队:深度森林挑战多标签学习,9大数据集超越传统方法
  9. 软考的计算机网络的IP地址应用
  10. vue-element-ui table动态合并