Android--利用相机或相册截取用户头像(解决了miui无法截取,以及部分机型拍照无返回Uri)

追风赶月莫停留,平芜尽处是春山。这篇文章主要讲述Android--利用相机或相册截取用户头像(解决了miui无法截取,以及部分机型拍照无返回Uri)相关的知识,希望能为你提供帮助。
声明 本文的Demo可用于从本地获取用户头像时使用, 解决了有些手机系统相机拍照后获取不到拍摄照片的问题, 以及解决小米miui系统调用系统裁剪图片功能camera.action.CROP后崩溃或重新打开app的问题。

  • 修改了部分机型拍照后返回的是缩略图的临时文件的问题。
如何获得一张原图 先看代码:
UtilClass.requestPermission(ChangeMyDataActivityCopy.this, android.Manifest.permission.CAMERA); chooseUserImageDialog = new ChooseImageDialog(mContext, new View.OnClickListener() { @ Override public void onClick(View v) { chooseUserImageDialog.dismiss(); switch (v.getId()) { case R.id.takePhotoBtn: { String state = Environment.getExternalStorageState(); if (state.equals(Environment.MEDIA_MOUNTED)) { Intent getImageByCamera = new Intent(" android.media.action.IMAGE_CAPTURE" ); // 获取文件 File tempFile = new File(PATH_ADD + " temp.jpg" ); if (tempFile.exists() & & tempFile.isFile()){ tempFile.delete(); } getImageByCamera.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile)); getImageByCamera.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); startActivityForResult(getImageByCamera, ChangeMyDataActivityPresenter.REQUEST_CODE_CAPTURE_CAMERA); } else { Toast.makeText(getApplicationContext(), " 请确认已经插入SD卡" , Toast.LENGTH_LONG).show(); } break; } case R.id.pickPhotoBtn: //Intent intent = new Intent(Intent.ACTION_PICK); //从相册中选取图片 Intent intent = new Intent(" android.intent.action.GET_CONTENT" ); //从相册/文件管理中选取图片 intent.setType(" image/*" ); //相片类型 startActivityForResult(intent, REQUEST_CODE_PICK_IMAGE); break; case R.id.cancelBtn: { break; } } } }); chooseUserImageDialog.showAtLocation(findViewById(R.id.mainLayout), Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0);

注解:
  1. Environment.getExternalStorageState是用来获取外部存储设备的状态, 即SD卡的状态, 这里为大家推荐一篇博文: Android中的Environment.getExternalStorageState使用
  2. android.media.action.IMAGE_CAPTURE为调用系统照相机
  3. Itent.ACTION_PICK 、Intent.ACTION_GET_CONTENT
两者都可以弹出一张选择列表, 两者都可以当作我们获取手机本地资源的途径, 通过设置Intent.setType(String type); 即可实现不同资源的选取, 不同的是Intent.ACTION_GET_CONTENT会弹出对话框选择资源的来源。常用的类型有:
//选择图片 requestCode 返回的标识 Intent innerIntent = new Intent(Intent.ACTION_GET_CONTENT); //" Android.intent.action.GET_CONTENT" innerIntent.setType(contentType); //查看类型 String IMAGE_UNSPECIFIED = " image/*" ; Intent wrapperIntent = Intent.createChooser(innerIntent, null); ((Activity) context).startActivityForResult(wrapperIntent, requestCode); //视频 Intent innerIntent = new Intent(Intent.ACTION_GET_CONTENT); innerIntent.setType(contentType); //String VIDEO_UNSPECIFIED = " video/*" ; Intent wrapperIntent = Intent.createChooser(innerIntent, null); ((Activity) context).startActivityForResult(wrapperIntent, requestCode); //添加音频 Intent innerIntent = new Intent(Intent.ACTION_GET_CONTENT); innerIntent.setType(contentType); //String VIDEO_UNSPECIFIED = " video/*" ; Intent wrapperIntent = Intent.createChooser(innerIntent, null); ((Activity) context).startActivityForResult(wrapperIntent, requestCode); //录音 Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType(ContentType.AUDIO_AMR); //String AUDIO_AMR = " audio/amr" ; intent.setClassName(" com.android.soundrecorder" , " com.android.soundrecorder.SoundRecorder" ); ((Activity) context).startActivityForResult(intent, requestCode);

更详细的使用请看博客: android之Itent.ACTION_PICK Intent.ACTION_GET_CONTENT妙用
  1. menuWindow.dismiss(); //在点击空白处的时候弹出窗口消失
  2. 【Android--利用相机或相册截取用户头像(解决了miui无法截取,以及部分机型拍照无返回Uri)】为什么获取的时候有时候拍照获得返回的Uri是一张缩略图?
    解决办法:
    Intent getImageByCamera = new Intent(" android.media.action.IMAGE_CAPTURE" ); // 获取文件 File tempFile = new File(PATH_ADD + " temp.jpg" ); if (tempFile.exists() & & tempFile.isFile()){ tempFile.delete(); } getImageByCamera.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile)); getImageByCamera.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); startActivityForResult(getImageByCamera, ChangeMyDataActivityPresenter.REQUEST_CODE_CAPTURE_CAMERA);

    调用系统拍照功能的时候先指定一个文件, 用于相机拍照后的临时文件的输出路径, 这样子即可避免在临时拍照的时候部分机型如( MIUI) 返回缩略图。
截取头像 reSizeImage(Uri uri)中为何不使用下列方法
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" , 100); intent.putExtra(" outputY" , 100); intent.putExtra(" return-data" , true); intent.putExtra(" output" , Uri.fromFile(new File(" /mnt/sdcard/temp" ))); //保存路径 startActivityForResult(intent, RESIZE_REQUEST_CODE);

上述方法中, 裁剪后的图片通过Intent的putExtra(“return-data”,true)方法进行传递, miui系统问题就出在这里, return-data的方式只适用于小图, miui系统默认的裁剪图片可能裁剪得过大, 或对return-data分配的资源不足, 造成return-data失败。
解决思路是: 裁剪后, 将裁剪的图片保存在Uri中, 在onActivityResult()方法中, 再提取对应的Uri图片转换为Bitmap使用。
其实大家直观也能感觉出来, Intent主要用于不同Activity之间通信, 是一种动态的小巧的资源占用, 类似于Http请求中的GET, 并不适用于传递图片之类的大数据。于是当A生成一个大数据要传递给B, 往往不是通过Intent直接传递, 而是在A生成数据的时候将数据保存到C, B再去调用C, C相当于一个转换的中间件。
即以下方法:
File outputImage = new File(MyConstants.PATH_ADD + " crop.jpg" ); try { if (outputImage.exists()) { outputImage.getAbsoluteFile().delete(); } outputImage.createNewFile(); } catch (Exception e) { e.printStackTrace(); } Uri userImageUri = Uri.fromFile(outputImage); Intent intent = new Intent(" com.android.camera.action.CROP" ); intent.setType(" image" ); intent.setDataAndType(imageUri, " image/*" ); // 下面这个crop= true是设置在开启的Intent中设置显示的VIEW可裁剪 intent.putExtra(" crop" , true); intent.putExtra(" scale" , true); intent.putExtra(" scaleUpIfNeeded" , true); // 去黑边 // aspectX aspectY 是宽高的比例 intent.putExtra(" aspectX" , 1); //输出是X方向的比例 intent.putExtra(" aspectY" , 1); // outputX outputY 是裁剪图片宽高, 切忌不要再改动下列数字, 会卡死 intent.putExtra(" outputX" , 500); //输出X方向的像素 intent.putExtra(" outputY" , 500); intent.putExtra(" noFaceDetection" , true); intent.putExtra(" return-data" , false); //设置为不返回数据 /** * 此方法返回的图片只能是小图片( 测试为高宽160px的图片) * 故将图片保存在Uri中, 调用时将Uri转换为Bitmap, 此方法还可解决miui系统不能return data的问题 */ //intent.putExtra(" return-data" , true); //intent.putExtra(" output" , Uri.fromFile(new File(" /mnt/sdcard/temp" ))); //保存路径 intent.putExtra(MediaStore.EXTRA_OUTPUT, userImageUri); //Log.d(TAG, " reSizeImage() called with: " + " uri = [" + userImageUri + " ]" ); activity.startActivityForResult(intent, REQUEST_RESIZE_REQUEST_CODE); return userImageUri;


主界面布局代码
< ?xml version= " 1.0" encoding= " utf-8" ?> < LinearLayout xmlns:android= " http://schemas.android.com/apk/res/android" android:orientation= " vertical" android:id= " @ + id/mainLayout" android:backgroundTint= " @ color/bisque" android:layout_width= " match_parent" android:layout_height= " match_parent" > < TextView android:textColor= " @ color/white" android:paddingLeft= " 20dp" android:gravity= " center_vertical|left" android:background= " @ color/brown" android:textSize= " 20sp" android:layout_width= " match_parent" android:layout_height= " 50dp" android:text= " 选择图片" /> < ImageView android:id= " @ + id/choose_image_image" android:layout_marginTop= " 50dp" android:layout_gravity= " center_horizontal" android:layout_width= " 100dp" android:layout_height= " 100dp" /> < /LinearLayout>


弹出窗口代码:
package com.example.no_clay.demolist.ChooseImage; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.drawable.ColorDrawable; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.PopupWindow; import com.example.no_clay.demolist.R; /** * Created by 寒 on 2016/6/4. */ class SelectPicPopupWindow extends PopupWindow { private Button takePhotoBtn, pickPhotoBtn, cancelBtn; private View mMenuView; @ SuppressLint(" InflateParams" ) public SelectPicPopupWindow(Context context, View.OnClickListener itemsOnClick) { super(context); LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); mMenuView = inflater.inflate(R.layout.choose_image_layout_dialog_pic, null); takePhotoBtn = (Button) mMenuView.findViewById(R.id.takePhotoBtn); pickPhotoBtn = (Button) mMenuView.findViewById(R.id.pickPhotoBtn); cancelBtn = (Button) mMenuView.findViewById(R.id.cancelBtn); cancelBtn.setOnClickListener(itemsOnClick); pickPhotoBtn.setOnClickListener(itemsOnClick); takePhotoBtn.setOnClickListener(itemsOnClick); this.setContentView(mMenuView); this.setWidth(ViewGroup.LayoutParams.MATCH_PARENT); this.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); this.setFocusable(true); this.setAnimationStyle(R.style.PopupAnimation); ColorDrawable dw = new ColorDrawable(0x80000000); this.setBackgroundDrawable(dw); mMenuView.setOnTouchListener(new View.OnTouchListener() {@ Override @ SuppressLint(" ClickableViewAccessibility" ) public boolean onTouch(View v, MotionEvent event) {int height = mMenuView.findViewById(R.id.pop_layout).getTop(); int y = (int) event.getY(); if (event.getAction() = = MotionEvent.ACTION_UP) { if (y < height) { dismiss(); } } return true; } }); } }


    推荐阅读