Refrence:
创新互联是一家专业提供远安企业网站建设,专注与网站建设、做网站、HTML5、小程序制作等业务。10年已为远安众多企业、政府机构等服务。创新互联专业网站制作公司优惠进行中。
Android 调用系统相机拍照适配主要经历了 6.0 7.0 10和11这几个大版本:
其中:
常用到的为 external-path 和 external-files-path,name和path按照自己需求编写
上述示例意思是,external-path标签指向的路径后path中指向的文件/文件夹拥有被访问权限,即 /storage/emulate/0/000 这个路径拥有被访问的权限。
简单示例:
最近项目中使用系统相机拍照,保存图片,发现一些问题。
读取图片旋转角度,然后再旋转回去。
使用BitmapFactory.Options,能更准确的获取图片格式,
判断地址末尾 .gif 有时候会不准确(不推荐)
上传服务器,一般使用地址,但是用户手动删除图片后,地址是无效的。为了防止地址无效,可以对需要上传图片地址做保存,但又希望系统读取不到,可以对保存地址进行修改。
读取图片地址api
我们可以去系统相册查看两张图片,会发现两张图片的地址是不一样的,而且两张图片的大小也不同。
出现2张的原因是:
(1)调用系统相机,拍照完成我们会生成一个保存地址,而这个地址是: /storage/android/data/包名/Picture/ ,这张是我们保存的拍照图片。
(2)相同的一张图片在哪?这个地址是:/storage/Pictures/ ,这张图片是系统复制的App目录下Pictures中的图片。
所以就会出现在系统相册两张图片,但两张图片大小不一致,地址不同。
调用系统api,只能读取到一张,是系统复制的那张,也就是 /storage/Pictures/ 目录下的这张,但是/storage/android/data/包名/Picture/ 目录下的没有读取到。
知道了问题,就有解决办法,可分为三种方法:
(1)第一种方法:
保存图片的时候,修改下地址(可参照标题 3 ,这样让系统无法识别出这张图片),结果就是,我读取不到,系统也别想读取不到,在系统相册里也就看不到这张图片。
(2)第二种方法:
因为api无法读取到,那我们就直接再读取/storage/android/data/包名/Picture/ 下的文件,把图片一块加入到同一个集合中用于展示,这样所有的图片都有了,但是系统相册中还是有两张图片,为解决这个问题。
(3)第三种方法:( )
在我们保存图片的时候,直接保存到 /storage/Pictures/ 这个目录下,也不用系统帮我们复制了,这样就只会出现一张,而且我们也能调用api直接读取到,两个问题全都解决了,完美!
(如果以上有错误或者有更优美的方式,感谢指出并改之,与君共勉)
这是我项目中出现的问题,希望能够帮助到你,Thanks,Bye!
相机使用基础之 调用系统中的相机应用
通过Intent直接调用系统相机
直接调用系统的相机应用,只需要在Intent对象中传入相应的参数即可,总体来说需要以下三步:
1. Compose a Camera Intent
MediaStore.ACTION_IMAGE_CAPTURE 拍照;
MediaStore.ACTION_VIDEO_CAPTURE录像。
2. Start the Camera Intent
使用startActivityForResult()方法,并传入上面的intent对象。
之后,系统自带的相机应用就会启动,用户就可以用它来拍照或者录像。
3. Receive the Intent Result
用onActivityResult()接收传回的图像,当用户拍完照片或者录像,或者取消后,系统都会调用这个函数。
关于接收图像
如果不设置接收图像的部分,拍照完毕后将会返回到原来的activity,相片会自动存储在拍照应用的默认存储位置。
为了接收图像,需要做以下几个工作:
1.指定图像的存储位置,一般图像都是存储在外部存储设备,即SD卡上。
你可以考虑的标准的位置有以下两个:
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
这个方法返回图像和视频的标准共享位置,别的应用也可以访问,如果你的应用被卸载了,这个路径下的文件是会保留的。
为了区分,你可以在这个路径下为你的应用创建一个子文件夹。
Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
这个方法返回的路径是和你的应用相关的一个存储图像和视频的方法。
如果应用被卸载,这个路径下的东西全都会被删除。
这个路径没有什么安全性限制,别的应用也可以自由访问里面的文件。
2.为了接收intent的结果,需要覆写activity中的 onActivityResult() 方法。
前面说过,可以不设置相机返回的图像结果的操作,此时在startActivityForResult()中不需要给intent传入额外的数据,这样在onActivityResult()回调时,返回的Intent data不为null,照片存在系统默认的图片存储路径下。
但是如果想得到这个图像,你必须制定要存储的目标File,并且把它作为URI传给启动的intent,使用MediaStore.EXTRA_OUTPUT作为关键字。
这样的话,拍摄出来的照片将会存在这个特殊指定的地方,此时没有thumbnail会被返回给activity的回调函数,所以接收到的Intent data为null。
这个很简单的,百度到处都有答案:
public class MainActivity extends Activity {
/** Called when the activity is first created. */
private Button button;
private ImageView view;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.button1);
view= (ImageView)findViewById(R.id.imageView1);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 1);
}
});
}
@SuppressLint("SdCardPath")
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
String sdStatus = Environment.getExternalStorageState();
if (!sdStatus.equals(Environment.MEDIA_MOUNTED)) { // 检测sd是否可用
Log.i("TestFile",
"SD card is not avaiable/writeable right now.");
return;
}
new DateFormat();
String name = DateFormat.format("yyyyMMdd_hhmmss",Calendar.getInstance(Locale.CHINA)) + ".jpg";
Toast.makeText(this, name, Toast.LENGTH_LONG).show();
Bundle bundle = data.getExtras();
Bitmap bitmap = (Bitmap) bundle.get("data");// 获取相机返回的数据,并转换为Bitmap图片格式
FileOutputStream b = null;
File file = new File("/sdcard/Image/");
file.mkdirs();// 创建文件夹
String fileName = "/sdcard/Image/"+name;
try {
b = new FileOutputStream(fileName);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, b);// 把数据写入文件
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
b.flush();
b.close();
} catch (IOException e) {
e.printStackTrace();
}
}
try
{
view.setImageBitmap(bitmap);// 将图片显示在ImageView里
}catch(Exception e)
{
Log.e("error", e.getMessage());
}
}
}
}
直接调用和间接调用。
1、ios相机拍照调用的是fuction方法直接调用相机启动程序,在启动和使用初期,同步识别其他功能及唤醒插件。
2、Android相机拍照调用的是user方法,下一步调用photo方法,再启动phoneP程序,逐步唤醒,流程式启动。
3、所以ios相机启动要比Android相机快,而且获取图片精度也高。
(1)申请权限
(2)设置布局
这里做了一个简单的布局:添加了一个按钮和一个ImageView控件用于显示拍摄的图像。
(3)为按钮添加点击事件监听
点击按钮时,调用系统相机进行拍照,并在确定后将图像显示在ImageView控件中。
(1)申请权限
(2)设置布局
添加了一个按钮和一个VideoView控件用于显示录制的视频。
(3)为按钮添加点击事件监听
同前面一样,点击按钮后调用系统相机进行录制视频,录制完成后点击确定即可将录制的视频显示在VideoView控件中。
对于Android11.0的版本,在调用系统相近进行视频录制的时候,即使在AndroidMenifest.xml中申请了CAMERA权限,还是会在程序运行时报错: Permission Denial , . .... .... with revoked permission android.permission.CAMERA
解决方法是在程序中动态申请权限:
写在最后:文章是在学习过程中做的学习笔记,同时与志同道合者分享,文章内容均经过我自己实验证实可行,如有问题欢迎留言,很高兴一起交流讨论,共同进步!