Android_照相机Camera_调用系统照相机返回data为空

1.调用系统照相机

//实例化一个intent,并指定action
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//指定一个图片路径对应的file对象
uri = Uri.fromFile(ImageUtil.getImageFile());
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
//启动activity
startActivityForResult(intent, REQUEST_CODE_CAMERA);
但是在onActivityResult(int requestCode, int resultCode, Intent data)代码中得到的data总为null

2.原因分析

于是我查看了Android系统框架Camera应用程序,找到了关于系统照相机如何处理返回值data问题!

默认情况下,即不需要指定intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);照相机有自己默认的存储路径,拍摄的照片将返回一个缩略图。如果想访问原始图片,可以通过dat extra能够得到原始图片位置。即,如果指定了目标uri,data就没有数据,如果没有指定uri,则data就返回有数据!现在想想,这种设计还是很合理的!

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	switch (requestCode) {
	case REQUEST_CODE_CAMERA:
		if (resultCode == RESULT_OK) {
			if(data !=null){ //可能尚未指定intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
				//返回有缩略图
				if(data.hasExtra("data")){
					Bitmap thumbnail = data.getParcelableExtra("data");
					//得到bitmap后的操作
				}
			}else{
				//由于指定了目标uri,存储在目标uri,intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
				// 通过目标uri,找到图片
				// 对图片的缩放处理
				// 操作
			}
		}
	}
}

3.Android系统照相机部分关键源码

// First handle the no crop case -- just return the value.  If the
// caller specifies a "save uri" then write the data to it's
// stream. Otherwise, pass back a scaled down version of the bitmap
// directly in the extras.
if (mSaveUri != null) {	//存在mSaveUri,即指定了目标uri
	OutputStream outputStream = null;
	try {
		outputStream = mContentResolver.openOutputStream(mSaveUri);
		outputStream.write(data);
		outputStream.close();

		setResult(RESULT_OK);	//直接返回RESULT_OK,并没有指定intent
		finish();
	} catch (IOException ex) {
		// ignore exception
	} finally {
		Util.closeSilently(outputStream);
	}
} else {
	Bitmap bitmap = createCaptureBitmap(data);
	// 返回RESULT_OK,并包含一个Intent对象,其中Extra中科key为data,value为一个bitmap
	setResult(RESULT_OK, new Intent("inline-data").putExtra("data", bitmap));
	finish();
}

4.常见问题及解决办法

如果我们设置了照片的存储路径,那么很可能会遇到一下三种问题:
问题一:onActivityResult 方法中的data 返回为空(数据表明,93%的机型的data 将会是Null,所以如果我们指定了路径,就不要使用data 来获取照片,起码在使用前要做空判断)
问题二:照片无法存储,如果自定义存储路径是/mnt/sdcard/lowry/,而手机SD 卡下在拍照前没有名为lowry 的文件夹,那么部分手机拍照后图片不会保存,导致我们无法获得照片,大多数手机的相机遇到文件夹不存在的情况都会自己创建出不存在的文件夹,而个别手机却不会创建,其代表机型为:三星I8258、华为H30-T00、红米等。解决的方法就是在指定存储路径前先判断路径中的文件夹是否都存在,不存在先创建再调用相机。
问题三:照片可以存储,但是名字不对
file:///mnt/sdcard/123 1.jpg,由于Uri 的fromFile 方法会将路径中的空格用“%20”取代。其实对于大多数的手机这都不算事,手机在解析存储路径的时候都会将“%20”替换为空格,这样实际上最终的照片名字还是我们当初指定的名字:123 1.jpg,遗憾的是个别手机(如酷派7260)系统自带的相机没有将“%20”读成空格,拍照后的照片的名字是123%201.jpg,我们用路径“file:///mnt/sdcard/123 1.jpg”能找到照片才怪!!


解决办法:

(1)使用 onActivityResult 中的 intent(data)前要做空判断。
(2)指定拍照路径时,先检查路径中的文件夹是否都存在,不存在时先创建文件夹再调用相机拍照。
(3)指定拍照存储路径时,照片的命名中不要包含空格等特殊符号。

  • 31
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
Android Studio 中调用相机需要以下几个步骤: 1. 在 AndroidManifest.xml 文件中添加相机的权限: ```xml <uses-permission android:name="android.permission.CAMERA" /> ``` 2. 在布局文件中添加一个用于预览相机的 SurfaceView 或 TextureView: ```xml <SurfaceView android:id="@+id/surfaceView" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` 3. 在相应的 Activity 或 Fragment 中获取 Camera 实例,并设置预览显示: ```java private Camera mCamera; private SurfaceView mSurfaceView; private SurfaceHolder mSurfaceHolder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mSurfaceView = findViewById(R.id.surfaceView); mSurfaceHolder = mSurfaceView.getHolder(); mSurfaceHolder.addCallback(this); } @Override public void surfaceCreated(SurfaceHolder holder) { // 打开相机并设置预览显示 mCamera = Camera.open(); try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); } catch (IOException e) { e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // 预览尺寸发生变化时处理 } @Override public void surfaceDestroyed(SurfaceHolder holder) { // 关闭相机释放资源 if (mCamera != null) { mCamera.stopPreview(); mCamera.release(); mCamera = null; } } ``` 4. 添加拍照功能,通过调用 `Camera.takePicture()` 方法实现: ```java private Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { // 处理拍照数据 Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); // 保存或展示拍照结果 } }; public void takePicture(View view) { if (mCamera != null) { mCamera.takePicture(null, null, mPictureCallback); } } ``` 以上是一个简单的调用相机并拍照的示例,你可以根据需要进行更加详细的定制和功能扩展。
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值