android获取并显示camera拍摄或者本地图库的照片
最近项目在搞用户图片上传功能,要从本地选择图片或者camera拍摄的图片显示预览并上传,之前为了方便一直想着用别人的轮子来造车,结果各种问题,要么应用崩溃,要么适配性极差,最后没办法,只能返璞归真,使用系统提供的方式来获取照片.然而,开发并不是一帆风顺的,网上提供的解决方案都是使用bitmap获取图片,得到的图片分辨率比较低,虽然网上找了很多文章,但很多都是答非所问,又或者一大堆问题,还不如自己慢慢琢磨研究.
在之前找了好多参考文章之后,都没能解决问题,有点绝望,没想到自己琢磨倒是搞好了.下面分享一波,也记录一下,方便日后使用.
先来看看最终实现的效果吧:
![]()
效果比较简单,只涉及到图片uri获取和展示,至于文件上传一般都是通过文件路径得到file,然后上传,本文并不介绍上传功能,大家可以自行研究,文章重点只为解决获取camera和本地图片模糊问题,下面来具体说明一下实现思路.
- 调用系统相机并设置输出路径
private void takePhoto() { //跳转到新的Activity去拍照片 //进来时就同时拥有两个权限,调用系统拍照 String state = Environment.getExternalStorageState(); if (state.equals(Environment.MEDIA_MOUNTED)) { Intent photoIn = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); String out_file_path = SAVED_IMAGE_DIR_PATH; File dir = new File(out_file_path); if (!dir.exists()) { dir.mkdirs(); } capturePath = dir.getAbsolutePath() + "/" + Calendar.getInstance().getTimeInMillis() + ".jpg"; loge("要保存图片的路径为===="+capturePath); File file = new File(capturePath); photoIn.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file)); photoIn.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); startActivityForResult(photoIn, TAKE_PHOTO_REQUEST); } else { Toast.makeText(getApplicationContext(), "请确认已经插入SD卡", Toast.LENGTH_LONG).show(); } }
通过MediaStore.EXTRA_OUTPUT方法可以设置拍照图片的输出路径,方便定位图片位置和使用
- 访问系统图库并返回图片uri
访问系统图库有多种方式,这里使用Intent.GET_ACTION_CONTENT,然后筛选image类型的资源,如下所示:
private void getSystemImage() { Intent localIntent = new Intent(); localIntent.setType("image/*"); /* 使用Intent.ACTION_GET_CONTENT这个Action */ localIntent.setAction(Intent.ACTION_GET_CONTENT); /* 取得相片后返回本画面 */ startActivityForResult(localIntent, CUT_PICTURE); }下面就要探究一下如何在onActivityResult()方法中接收图片数据的问题了.
- 获取返回的图片uri
之前说过,一般情况下,都是使用bitmap来获取到图片并显示,这样获取的好处在于得到的图片是缩略图,不会占用太多资源,但是同样也会带来一个问题:如果我们需要得到高质量或者原图,bitmap的方式就无法达到需求,因为android系统内部作了相关限制,即使是最高质量的bitmap,最终也看起来不会清晰.那么有什么方法可以解决问题呢?答案肯定是有的. 先来看看下面的这部分onActivityResult()代码:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // super.onActivityResult(requestCode, resultCode, data); loge("拍照完了==" + resultCode); if (requestCode == TAKE_PHOTO_REQUEST && resultCode == RESULT_OK) { isCameraImage = true; isLocalImage = false; loge("拍照成功,拍照路径为"+capturePath); File file = new File(capturePath); uploadImagePath = capturePath; Uri uri = Uri.fromFile(file); showUploadImage(uri.toString()); } else if (requestCode == TAKE_PHOTO_REQUEST && resultCode != RESULT_OK) { loge("取消了拍照"); } else if(requestCode == CUT_PICTURE && resultCode == RESULT_OK){ isLocalImage = true; isCameraImage =false; localUri = data.getData(); loge("传回来的本地图片uri为==="+localUri.toString()); showUploadImage(localUri.toString()); } }
从代码中不难看出,最终我们想要得到的都是图片的uri,有人可能会问为什么要得到uri而不是file,当然是因为我们要快速展示出来,没错,就是使用glide来展示.刚刚takePhoto()中capturePath是作为拍照图片保存的输出路径,在onActivityResult()拍照成功返回后,获取file,并得到uri,进而得以显示原图片,并没有通过bitmap来显示.
至于从本地图库选择图片后返回,我们可以直接得到图片的uri. 由于本地图片选择并不会改变路径,所以无法为其向前者一样指定输出路径,但是uri就是我们最终希望得到的.OK,这样就算大功告成了,下面附上showUploadImage()显示返回图片的方法:
private void showUploadImage(String imageUri) { if(imageUri!=null){ add_back_view.setVisibility(View.GONE); iv_upload_image.setVisibility(View.VISIBLE); Glide .with(this) .load(imageUri) .centerCrop() .thumbnail(0.3f) .into(iv_upload_image); bt_upload.setEnabled(true); bt_upload.setAlpha(1); } }
- 如果想要得到图片文件用于上传至服务器那该怎么办?
String[] proj = { MediaStore.Images.Media.DATA }; Cursor actualimagecursor = managedQuery(localUri,proj,null,null,null); int actual_image_column_index = actualimagecursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); actualimagecursor.moveToFirst(); String img_path = actualimagecursor.getString(actual_image_column_index);没看错,就是这短短几行代码就能得到image的路径,接下来就可以放心的上传图片啦