其实android拍照这个地方还是有很多注意事项的,我在上个项目中就遇到一些坑,因此我想把它记录下来,希望能帮助一些跟我遇到的同样的问题的人

如果你在项目中遇到以下问题:

  • 通过系统路径,拍出来的图片不清楚
  • 在某些情况下,onActivityResult(int requestCode, int resultCode, Intent data) 回调方法中,data为null
  • 有些时候,在某些手机拍照之后会闪退,报空指针错误,等等
  • 有些时候在拍完照片之后,点击确认按钮之后,无法返回到前一个Activity

可以继续往下看,否则的话,就跳过吧,不能耽误你的时间

先说第一种情况,如果直接调用系统相机,一般系统会把图片放在默认的路径,然后通过回调函数onActivityResult(int requestCode, int resultCode, Intent data)中的data拿值,Bitmap bitmap =(Bitmap) data.getExtras().get("data"),这样就拿到bitmap了。值得注意的是,返回的这个图片是缩略图并不是原图。如果是需要拍身份证照片,录入信息的,不能用考虑这种。当然这种调用相机也会有人用到,先贴一下代码:

 public class MainActivity extends AppCompatActivity {public static final int TAKE_PHOTO = 111;private Button mButton;private ImageView mImageView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mButton = (Button) findViewById(R.id.takePhoto);mImageView = (ImageView) findViewById(R.id.img);mButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {takePhoto();}});}public void takePhoto() {Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);startActivityForResult(captureIntent, TAKE_PHOTO);}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (resultCode == RESULT_OK) {if (requestCode == TAKE_PHOTO) {Bitmap bitmap = (Bitmap) data.getExtras().get("data");//拿到bitmap,做喜欢做的事情把  ---> 显示 or上传?mImageView.setImageBitmap(bitmap);//upload}}}}

第二种情况,onActivityResult(int requestCode, int resultCode, Intent data) 回调方法中,data为null。这种情况,如果代码没错误,那么产生这种原因是什么呢? 其实当你自定义拍照路径之后,回调函数中,返回的data就为null了,那么你拿图片资源就只能通过file转化成bitmap的了。下面我会把Bitmap工具类提供出来

public class MainActivity extends AppCompatActivity {public static final int TAKE_PHOTO = 111;private Button mButton;private ImageView mImageView;//保存 照片的目录private String path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "mms";private File photo_file = new File(path);private String photoPath ;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mButton = (Button) findViewById(R.id.takePhoto);mImageView = (ImageView) findViewById(R.id.img);mButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {takePhoto();}});}public void takePhoto() {Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);if (!photo_file.exists()) {photo_file.mkdirs();}photo_file = new File(path, "/temp.jpg");photoPath = path + "/temp.jpg";if (photo_file != null) {captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo_file));startActivityForResult(captureIntent, TAKE_PHOTO);}}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (resultCode == RESULT_OK) {if (requestCode == TAKE_PHOTO) {//这种情况下 data是为null的,因为自定义了路径}}}}

这种情况下,因为data为null,所以正确做法应该是从 photoPath中来获取bitmap。在后面会写出全部代码的,这里只是说明为啥data会为null

在某些手机拍照之后会闪退,报空指针错误。这个错误主要是因为 当点击拍照时,某些情况下,系统会认为这个是耗费资源的操作,所以会未经你允许的情况下把之前的Activity给销毁了,所以当再次回到上个界面中,生命周期会重新来一遍,所以当执行到onActivityResult(int requestCode, int resultCode, Intent data)中,photoPath还是为空,所以报了空指针异常。解决办法如下:

   @Overrideprotected void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);outState.putString("photoPath", photoPath);Log.d(TAG, "onSaveInstanceState");}@Overrideprotected void onRestoreInstanceState(Bundle savedInstanceState) {super.onRestoreInstanceState(savedInstanceState);if (TextUtils.isEmpty(photoPath)) {photoPath = savedInstanceState.getString("photoPath");}Log.d(TAG, "onRestoreInstanceState");}

通过onSaveInstanceState(Bundle outState)把数据保存起来,然后界面确实被系统销毁了,那么就会执行onRestoreInstanceState(Bundle savedInstanceState)方法,在这个方法中就可以取到数据了,从而恢复界面。

有些时候在拍完照片之后,点击确认按钮之后,无法返回到前一个Activity,这个问题主要是文件建的不对,导入图片资源无法写进去,点击确定后也无法回退到上个界面。这里就按照我这种创建的方式把。

完整拍照上传图片的代码如下:
public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";public static final int TAKE_PHOTO = 111;private Button mButton;private ImageView mImageView;//保存 照片的目录private String path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "mms";private File photo_file = new File(path);private String photoPath;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mButton = (Button) findViewById(R.id.takePhoto);mImageView = (ImageView) findViewById(R.id.img);mButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {takePhoto();}});}public void takePhoto() {Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);if (!photo_file.exists()) {photo_file.mkdirs();}photo_file = new File(path, "/temp.jpg");photoPath = path + "/temp.jpg";if (photo_file != null) {captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo_file));startActivityForResult(captureIntent, TAKE_PHOTO);}}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (resultCode == RESULT_OK) {if (requestCode == TAKE_PHOTO) {//这中情况下 data是为null的,因为自定义了路径 所以通过这个路径来获取Bitmap smallBitmap = BitmapUtil.getSmallBitmap(photoPath);// ok 拿到图片的base64 上传String base64 = BitmapToBase64Util.bitmapToBase64(smallBitmap);}}}@Overrideprotected void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);outState.putString("photoPath", photoPath);Log.d(TAG, "onSaveInstanceState");}@Overrideprotected void onRestoreInstanceState(Bundle savedInstanceState) {super.onRestoreInstanceState(savedInstanceState);if (TextUtils.isEmpty(photoPath)) {photoPath = savedInstanceState.getString("photoPath");}Log.d(TAG, "onRestoreInstanceState");}}

BitmapUtil

@SuppressLint("NewApi")
public class BitmapUtil {// 计算图片的缩放值public static int calculateInSampleSize(BitmapFactory.Options options,int reqWidth, int reqHeight) {final int height = options.outHeight;final int width = options.outWidth;int inSampleSize = 1;if (height > reqHeight || width > reqWidth) {final int heightRatio = Math.round((float) height/ (float) reqHeight);final int widthRatio = Math.round((float) width / (float) reqWidth);inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;}return inSampleSize;}// 根据路径获得图片并压缩,返回bitmap用于显示public static Bitmap getSmallBitmap(String filePath) {final BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeFile(filePath, options);// Calculate inSampleSizeoptions.inSampleSize = calculateInSampleSize(options, 200, 380);// Decode bitmap with inSampleSize setoptions.inJustDecodeBounds = false;return BitmapFactory.decodeFile(filePath, options);}// 根据路径获得图片并压缩,返回bitmap用于显示public static Bitmap getSmallBitmap(InputStream is) {final BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeStream(is, null, options);// Calculate inSampleSizeoptions.inSampleSize = calculateInSampleSize(options, 480, 800);// Decode bitmap with inSampleSize setoptions.inJustDecodeBounds = false;return BitmapFactory.decodeStream(is, null, options);}public static Bitmap comp(Bitmap image) {ByteArrayOutputStream baos = new ByteArrayOutputStream();image.compress(Bitmap.CompressFormat.JPEG, 100, baos);if (baos.toByteArray().length / 1024 > 1024) {// 判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出baos.reset();// 重置baos即清空baosimage.compress(Bitmap.CompressFormat.JPEG, 40, baos);// 这里压缩50%,把压缩后的数据存放到baos中}ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());BitmapFactory.Options newOpts = new BitmapFactory.Options();// 开始读入图片,此时把options.inJustDecodeBounds 设回true了newOpts.inJustDecodeBounds = true;Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);newOpts.inJustDecodeBounds = false;int w = newOpts.outWidth;int h = newOpts.outHeight;// 现在主流手机比较多是800*480分辨率,所以高和宽我们设置为float hh = 800f;// 这里设置高度为800ffloat ww = 480f;// 这里设置宽度为480f// 缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可int be = 1;// be=1表示不缩放if (w > h && w > ww) {// 如果宽度大的话根据宽度固定大小缩放be = (int) (newOpts.outWidth / ww);} else if (w < h && h > hh) {// 如果高度高的话根据宽度固定大小缩放be = (int) (newOpts.outHeight / hh);}if (be <= 0)be = 1;newOpts.inSampleSize = be;// 设置缩放比例// 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了isBm = new ByteArrayInputStream(baos.toByteArray());bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);return compressImage(bitmap);// 压缩好比例大小后再进行质量压缩}// 把bitmap转换成Stringpublic static String bitmapToString(String filePath) {Bitmap bm = getSmallBitmap(filePath);ByteArrayOutputStream baos = new ByteArrayOutputStream();bm.compress(Bitmap.CompressFormat.JPEG, 40, baos);byte[] b = baos.toByteArray();return Base64.encodeToString(b, Base64.DEFAULT);}/***  质量压缩* @param image* @return*/public static Bitmap compressImage(Bitmap image) {ByteArrayOutputStream baos = new ByteArrayOutputStream();image.compress(Bitmap.CompressFormat.JPEG, 50, baos);// 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中int options = 50;while (baos.toByteArray().length / 1024 > 100) { // 循环判断如果压缩后图片是否大于100kb,大于继续压缩baos.reset();// 重置baos即清空baosimage.compress(Bitmap.CompressFormat.JPEG, options, baos);// 这里压缩options%,把压缩后的数据存放到baos中options -= 10;// 每次都减少10}ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());// 把压缩后的数据baos存放到ByteArrayInputStream中Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);// 把ByteArrayInputStream数据生成图片return bitmap;}/*** 根据Uri获取图片绝对路径,解决Android4.4以上版本Uri转换* @param context* @param imageUri* @author yaoxing* @date 2014-10-12*/public static String getImageAbsolutePath(Activity context, Uri imageUri) {if (context == null || imageUri == null)return null;if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, imageUri)) {if (isExternalStorageDocument(imageUri)) {String docId = DocumentsContract.getDocumentId(imageUri);String[] split = docId.split(":");String type = split[0];if ("primary".equalsIgnoreCase(type)) {return Environment.getExternalStorageDirectory() + "/" + split[1];}} else if (isDownloadsDocument(imageUri)) {String id = DocumentsContract.getDocumentId(imageUri);Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));return getDataColumn(context, contentUri, null, null);} else if (isMediaDocument(imageUri)) {String docId = DocumentsContract.getDocumentId(imageUri);String[] split = docId.split(":");String type = split[0];Uri contentUri = null;if ("image".equals(type)) {contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;} else if ("video".equals(type)) {contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;} else if ("audio".equals(type)) {contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;}String selection = MediaStore.Images.Media._ID + "=?";String[] selectionArgs = new String[] { split[1] };return getDataColumn(context, contentUri, selection, selectionArgs);}} // MediaStore (and general)else if ("content".equalsIgnoreCase(imageUri.getScheme())) {// Return the remote addressif (isGooglePhotosUri(imageUri))return imageUri.getLastPathSegment();return getDataColumn(context, imageUri, null, null);}// Fileelse if ("file".equalsIgnoreCase(imageUri.getScheme())) {return imageUri.getPath();}return null;}public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {Cursor cursor = null;String column = MediaStore.Images.Media.DATA;String[] projection = { column };try {cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);if (cursor != null && cursor.moveToFirst()) {int index = cursor.getColumnIndexOrThrow(column);return cursor.getString(index);}} finally {if (cursor != null)cursor.close();}return null;}/**** 图片的缩放方法** @param bgimage*            :源图片资源* @param newWidth*            :缩放后宽度* @param newHeight*            :缩放后高度* @return*/public static Bitmap zoomImage(Bitmap bgimage, double newWidth,double newHeight) {// 获取这个图片的宽和高float width = bgimage.getWidth();float height = bgimage.getHeight();// 创建操作图片用的matrix对象Matrix matrix = new Matrix();// 计算宽高缩放率float scaleWidth = ((float) newWidth) / width;float scaleHeight = ((float) newHeight) / height;// 缩放图片动作matrix.postScale(scaleWidth, scaleHeight);Bitmap bitmap = Bitmap.createBitmap(bgimage, 0, 0, (int) width,(int) height, matrix, true);return bitmap;}/*** @param uri The Uri to check.* @return Whether the Uri authority is ExternalStorageProvider.*/public static boolean isExternalStorageDocument(Uri uri) {return "com.android.externalstorage.documents".equals(uri.getAuthority());}/*** @param uri The Uri to check.* @return Whether the Uri authority is DownloadsProvider.*/public static boolean isDownloadsDocument(Uri uri) {return "com.android.providers.downloads.documents".equals(uri.getAuthority());}/*** @param uri The Uri to check.* @return Whether the Uri authority is MediaProvider.*/public static boolean isMediaDocument(Uri uri) {return "com.android.providers.media.documents".equals(uri.getAuthority());}/*** @param uri The Uri to check.* @return Whether the Uri authority is Google Photos.*/public static boolean isGooglePhotosUri(Uri uri) {return "com.google.android.apps.photos.content".equals(uri.getAuthority());}
}

BitmapUtil工具类主要包含了获取bitmap、质量压缩等一些方法。当然拍照之后一般会获取图片的base64,然后上传给服务端,或者前端js。 BitmapToBase64Util代码如下;

BitmapToBase64Util

public class BitmapToBase64Util {/*** bitmapתΪbase64** @param bitmap* @return*/public static String bitmapToBase64(Bitmap bitmap) {String result = null;ByteArrayOutputStream baos = null;try {if (bitmap != null) {baos = new ByteArrayOutputStream();bitmap.compress(Bitmap.CompressFormat.JPEG, 50, baos);  //这里50表示压缩50%baos.flush();baos.close();byte[] bitmapBytes = baos.toByteArray();result = Base64.encodeToString(bitmapBytes, Base64.DEFAULT);}} catch (Exception e) {e.printStackTrace();} finally {try {if (baos != null) {baos.flush();baos.close();}} catch (Exception e) {e.printStackTrace();}}return result;}/*** base64תΪbitmap** @param base64Data* @return*/public static Bitmap base64ToBitmap(String base64Data) {byte[] bytes = Base64.decode(base64Data, Base64.DEFAULT);return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);}
}
关于调用系统相机、拍照上传就到处为止,希望能帮助到一些需要帮助的人

Android 调用系统相机,拍照,并上传图片所注意的一些问题相关推荐

  1. Android调用系统相机拍照并保存到指定位置

    Android调用系统相机拍照并保存到指定位置 @Click(R.id.btn_takePhoto)void onclick() {Intent intent = new Intent(MediaSt ...

  2. android固定位置拍照,Android调用系统相机拍照并保存到指定位置

    Android调用系统相机拍照并保存到指定位置 @Click(R.id.btn_takePhoto) void onclick() { Intent intent = new Intent(Media ...

  3. android 调用系统相机拍照 获取原图

    博客源址:android 调用系统相机拍照 获取原图 博客时间:2013-04-23 11:08 好吧,为了这个问题又折腾了一整天.之前在网上找来的方法,如果在onActivityResult中直接用 ...

  4. Android调用系统相机拍照

    参考: Taking Photos Simply FileProvider 项目地址(好多人找我要,我传到百度云啦,大家自取):链接:https://pan.baidu.com/s/1nWsoE0eS ...

  5. android异常相机处理,android 调用系统相机拍照的各种异常处理

    1 本文只讨论调用系统相机出现的异常解决办法下面是调用系统相机的代码 先看一下最简单的写法 Intent intent = new Intent(android.provider.MediaStore ...

  6. android相机保存文件为空,android 调用系统相机拍照,返回的data为null

    最近做项目,需要拍照功能,于是就想简单的调用系统相机来完成这一需求(当然,如果想要个性化一点的,也可以自定义camera去实现,这里暂时不做). if(Environment.getExternalS ...

  7. Android 调用系统相机拍照和录制视频,保存照片和视频

    1.申请权限 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> ...

  8. android 调用系统相机拍照并返回路径,Android调用相机拍照并返回路径和…

    调用系统图库: Intent intent = new Intent(Intent.ACTION_PICK,MediaStore.Images.Media.EXTERNAL_CONTENT_URI); ...

  9. Android 调用系统相机拍照,生命周期重走OnCreate,导致无数据的解决办法

    extends:http://blog.csdn.net/b275518834/article/details/42347903 BUG具体体现为 : (1) 摄像头拍照后图片数据不一定能返回 ; o ...

  10. Android调用系统相机拍照像素太低以及内存溢出问题

    在Android移动开发过程中,如果直接按照原生方式进行拍照经常会出现像素太低(可能只有几十KB),照片非常模糊的问题. Activity中启动相机的代码: Intent openCameraInte ...

最新文章

  1. Intel Realsense D435 C/C++调用code examples(附代码)(坑坑坑坑坑!!!)(opencv显示图片反色解决)
  2. phpstudy使用(80端口被system占用,无法关闭和删除)
  3. python编程书籍资料整理大全
  4. devops测试_使用DevOps管道自动执行用户验收测试
  5. pygame为游戏添加背景_用 Python 制作飞机大战小游戏
  6. Struts2 + Hibernate + Spring 以及javaweb模块问题解决(2)
  7. 关于php正则表达式得选择题,经典PHP笔试题
  8. 机器学习基础-朴素贝叶斯分类
  9. MySQL数据库(八)
  10. 金蝶k3系统中间服务器不可用,【金蝶软件】客户端登陆时提示远程服务器不存在或不可用(金蝶K3系统)...
  11. 百度指数抓取-趋势截图+估算方法
  12. 当前linux的ks文件,高手请进!请教linux自动安装文件ks.cfg
  13. python中item是什么意思中文-python中的item
  14. Redhat7.5升级openssh到8.2p1
  15. MT4-EA自动化交易研究笔记(2022-06-24)
  16. 反函数的导数——arcsinx的导数求导证明
  17. MATLAB识别实验,Matlab在图像处理与目标识别方面的应用实验
  18. 常见的云服务器运营商及相关的优惠活动
  19. 基于SpringBoot旅游信息管理系统网站
  20. 酷!一个仿漫画手绘风格的 Python 图表库

热门文章

  1. SQL语句之OR和AND的混合使用
  2. 微信小程序 图文混编 重写picker组件
  3. 焊接工业机器人实训系统平台
  4. 被冷落的轻薄手机,512GB+144Hz高刷曲面屏+旗舰芯,跌至2649元
  5. 只有善用能力才能充分发挥
  6. 我死了,我装的:米聊死而复生背后,是小米与腾讯十年的明争暗斗
  7. 如何布置电脑文件夹、电脑文件路径、浏览器收藏夹
  8. JNA 调用 DLL
  9. java hook jna鼠标_JNA介绍及使用JNA监听鼠标实现
  10. 用GNS3模拟器做链路聚合实验