Android 调用系统相机拍照并且显示在相册中,以及中间可能会遇到的一些问题的解决
2017-04-14 15:06
1086 查看
主要思路是在使用照相机拍照,然后为拍得的照片在SD卡新开一个储存照片的文件
代码:因为要调用照相机和SD卡所以需要添加以下权限:
activity_main.xml中
MainActivity中:
startActivityForResult(intent, CAMERA_RESULT);//跳转界面传回拍照所得数据
} catch (Exception e) {
}
}
}
public String getSDPath(){
File sdDir = null;
boolean sdCardExist = Environment.getExternalStorageState() .equals(android.os.Environment.MEDIA_MOUNTED); //判断sd卡是否存在
if (sdCardExist){ sdDir = Environment.getExternalStorageDirectory();//获取跟目录
}
return sdDir.toString(); }
private String getPhotoFileName() {
Date date = new Date(System.currentTimeMillis());
SimpleDateFormat dateFormat = new SimpleDateFormat( "'IMG'_yyyyMMdd_HHmmss");
return dateFormat.format(date) +".jpg
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAMERA_RESULT) {
Bitmap bitmap = BitmapFactory.decodeFile(mPhotoPath, null);
mImageView.setImageBitmap(bitmap); }
}
}
下面对获取SD卡路径进行补充,有两种情况,我用了第二种
用第二种需要加一个包
获取sd卡路径
方法一: private String folder = "/sdcard/DCIM/Camera/"(SD卡上拍照程序的图片存储路径); //写死绝对路径,不赞成使用
方法二:
public String getSDPath(){
File sdDir = null;
boolean sdCardExist = Environment.getExternalStorageState()
.equals(Android.os.Environment.MEDIA_MOUNTED);
//判断sd卡是否存在
if (sdCardExist)
{
sdDir = Environment.getExternalStorageDirectory();//获取跟目录
}
return sdDir.toString();
}
然后:在后面加上斜杠,在加上文件名
String fileName = getSDPath() +"/" + name;//以name存在目录中
期间遇到了一个问题就是:调用系统照相机在onActivityResult()中返回的data为空。
默认情况下,即不需要指定intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);照相机有自己默认的存储路径,拍摄的照片将返回一个缩略图。如果想访问原始图片,可以通过dat extra能够得到原始图片位置。即,如果指定了目标uri,data就没有数据,如果没有指定uri,则data就返回有数据!现在想想,这种设计还是很合理的!
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
@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,找到图片
// 对图片的缩放处理
// 操作
}
}
}
}
Android系统照相机部分关键源码
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
// 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();
}
问题一: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”能找到照片才怪!!
![](https://oscdn.geek-share.com/Uploads/Images/Content/201908/31/c64f99d007e653adf846351610e9f500)
(2)指定拍照路径时,先检查路径中的文件夹是否都存在,不存在时先创建文件夹再调用相机拍照。
(3)指定拍照存储路径时,照片的命名中不要包含空格等特殊符号。
参考博文链接:http://blog.csdn.net/zimo2013/article/details/16916279;http://blog.csdn.net/a751608624/article/details/50728336;http://blog.csdn.net/llxlqy/article/details/51280564;http://www.cnblogs.com/dongweiq/p/6478393.html
代码:因为要调用照相机和SD卡所以需要添加以下权限:
在manifests中添加
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
activity_main.xml中
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <Button android:id="@+id/button" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="点击按钮拍照" /> <ImageView android:id="@+id/imageView" android:layout_below="@id/button" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout>
MainActivity中:
package com.example.administrator.myapplication1; import android.graphics.BitmapFactory; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import java.io.IOException; import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore; import android.app.Activity; import android.content.ContentResolver; import android.content.Intent; import android.graphics.Bitmap; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ImageView; import android.os.Environment; import java.io.FileOutputStream; import java.io.File; import java.io.File; import java.text.SimpleDateFormat; import java.util.Date; import android.app.Activity; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.os.Environment; public class MainActivity extends AppCompatActivity { private Button mButton; private ImageView mImageView;//用于显示照片 private File mPhotoFile; private String mPhotoPath; public final static int CAMERA_RESULT = 1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mButton = (Button) findViewById(R.id.button); mButton.setOnClickListener(new ButtonOnClickListener()); mImageView = (ImageView) findViewById(R.id.imageView); } private class ButtonOnClickListener implements View.OnClickListener { public void onClick(View v) { try { Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");//开始拍照 mPhotoPath = getSDPath()+"/"+ getPhotoFileName();//设置图片文件路径,getSDPath()和getPhotoFileName()具体实现在下面 mPhotoFile = new File(mPhotoPath); if (!mPhotoFile.exists()) { mPhotoFile.createNewFile();//创建新文件 } intent.putExtra(MediaStore.EXTRA_OUTPUT,//Intent有了图片的信息 Uri.fromFile(mPhotoFile));
// 发送广播通知相册更新数据。显示所拍摄的照片 Context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(mPhotoFile)));
startActivityForResult(intent, CAMERA_RESULT);//跳转界面传回拍照所得数据
} catch (Exception e) {
}
}
}
public String getSDPath(){
File sdDir = null;
boolean sdCardExist = Environment.getExternalStorageState() .equals(android.os.Environment.MEDIA_MOUNTED); //判断sd卡是否存在
if (sdCardExist){ sdDir = Environment.getExternalStorageDirectory();//获取跟目录
}
return sdDir.toString(); }
private String getPhotoFileName() {
Date date = new Date(System.currentTimeMillis());
SimpleDateFormat dateFormat = new SimpleDateFormat( "'IMG'_yyyyMMdd_HHmmss");
return dateFormat.format(date) +".jpg
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAMERA_RESULT) {
Bitmap bitmap = BitmapFactory.decodeFile(mPhotoPath, null);
mImageView.setImageBitmap(bitmap); }
}
}
下面对获取SD卡路径进行补充,有两种情况,我用了第二种
用第二种需要加一个包
import android.os.Environment;
获取sd卡路径
方法一: private String folder = "/sdcard/DCIM/Camera/"(SD卡上拍照程序的图片存储路径); //写死绝对路径,不赞成使用
方法二:
public String getSDPath(){
File sdDir = null;
boolean sdCardExist = Environment.getExternalStorageState()
.equals(Android.os.Environment.MEDIA_MOUNTED);
//判断sd卡是否存在
if (sdCardExist)
{
sdDir = Environment.getExternalStorageDirectory();//获取跟目录
}
return sdDir.toString();
}
然后:在后面加上斜杠,在加上文件名
String fileName = getSDPath() +"/" + name;//以name存在目录中
期间遇到了一个问题就是:调用系统照相机在onActivityResult()中返回的data为空。
原因分析
于是我查看了Android系统框架Camera应用程序,找到了关于系统照相机如何处理返回值data问题!默认情况下,即不需要指定intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);照相机有自己默认的存储路径,拍摄的照片将返回一个缩略图。如果想访问原始图片,可以通过dat extra能够得到原始图片位置。即,如果指定了目标uri,data就没有数据,如果没有指定uri,则data就返回有数据!现在想想,这种设计还是很合理的!
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
@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,找到图片
// 对图片的缩放处理
// 操作
}
}
}
}
Android系统照相机部分关键源码
[java]view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
// 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();
}
常见问题及解决办法
如果我们设置了照片的存储路径,那么很可能会遇到一下三种问题:问题一: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)指定拍照存储路径时,照片的命名中不要包含空格等特殊符号。
参考博文链接:http://blog.csdn.net/zimo2013/article/details/16916279;http://blog.csdn.net/a751608624/article/details/50728336;http://blog.csdn.net/llxlqy/article/details/51280564;http://www.cnblogs.com/dongweiq/p/6478393.html
相关文章推荐
- Android 拍照以及一些常用的处理,例如将图片显示到相册(包含了安卓系统6.0以上调用相机的处理)
- 解决Android调用系统相机拍照后相片无法在相册中显示问题
- Android多层嵌套Fragment中调用系统相机拍照以及裁剪的相关问题解决
- android调用系统相机的方法,并且解决三星手机遇到的问题,图片旋转、压缩
- Android开发 调用系统相机相册图片功能,解决小米手机拍照或者图片横竖相反问题,及小米手机相册图片路径问题
- android调用系统相机的方法,并且解决三星手机遇到的问题
- android调用系统相机和相册进行拍照裁剪处理,解决不同安卓版本存在无法加载相册的问题,处理了是否有sd卡的存在的情况
- 解决三星调用系统相机拍照显示图片旋转90度横着的问题
- Android 调用系统相机拍照保存以及调用系统相册的方法
- Android拍照保存在系统相册不显示的问题解决方法
- Android 调用系统相机拍照保存以及调用系统相册的方法
- Android 调用系统相机拍照保存以及调用系统相册的方法
- Android 调用系统相机拍照保存以及调用系统相册的方法
- android调用系统相机(通用,完美解决4.0以后版本以及机型的问题)
- Android基础--调用系统相机,打开相册,展示到界面,出现的一些问题Uri为空,data为null,图片错乱问题
- 调用系统相机拍照获取图片或者从相册中调用本地图片显示问题
- 解决Android拍照保存在系统相册不显示的问题
- 解决Android拍照保存在系统相册不显示的问题
- 解决Android拍照保存在系统相册不显示的问题
- 解决Android拍照保存在系统相册不显示的问题