【Android Developers Training】 48. 轻松拍摄照片
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好。
原文链接:http://developer.android.com/training/camera/photobasics.html
这节课将展示如何使用已经存在的相机应用拍摄相机。
假设你现在在实现一个基于人群的气象服务,它构建一个全球的气象地图,通过将运行了你的应用色设备所拍摄的天空照片拼接起来来实现这个气象地图。整合照片只是你的应用的一小部分。你希望通过最简单地方式拍摄照片,而不是需要重新构造一个相机。大多数Android设备其实已经至少有了一个相机应用。在这节课中,你将学习如何利用它来为您拍摄一个照片。
一). 请求相机权限
如果你的应用中一个重要的函数会拍摄照片,同时限制只有那些拥有相机的设备可以在Google Play上下载。为了声明你的应用依赖于一个相机,在你的清单文件中放置一个<uses-feature>标签:
<manifest ... >
<uses-feature android:name="android.hardware.camera"
android:required="true" />
...
</manifest>
如果你的应用使用,但并不依赖一个相机来执行功能,那么将“android:required”设置为“false”。这样的话,那么Google Play将会允许没有相机的设备下载你的应用。那么接下来就是你的责任在运行时如果调用了需要用相机的函数时,通过调用hasSystemFeature(PackageManager.FEATURE_CAMERA)检查是否可以获取相机。如果相机无法获取,那么你就应该禁止你的相关功能特性。
二). 使用相机应用拍摄照片
在Android中向其它应用分发意图是通过激活一个描述你的意图的Intent。这一过程分为三步:Intent自身,调用外部Activity,当焦点回到你的activity中处理图像数据的一些代码。
下面的代码是构造一个intent来获取一张照片。
static final int REQUEST_IMAGE_CAPTURE = 1; private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
注意这里startActivityForResult()方法被一个前提所保护,那就是通过调用resolveActivity(),返回第一个可以处理该intent的组件。执行这个检查时很重要的因为如果你调用了startActivityForResult()并使用一个没有一个应用可以处理的intent,你的应用将会崩溃。所以只要结果不是null,那么使用这个intent是安全的。
三). 获取缩略图
如果简单地获取照片不是你的应用的终极目标,那么你可能希望从相机应用收回图像并做一些事情。
Android相机应用在onActivityResult()中传递的Intent内,将照片编码并作为一个小的位图(Bitmap)在“extras”,在键“data”下。下面的代码将会获得一个图像并在ImageView中显示。
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
mImageView.setImageBitmap(imageBitmap);
}
}
Note:
这个来自“data”的缩略图用作图标hi非常好的,但是如果用作更大的图片就不行了。处理全尺寸的图片需要更多操作。
四). 保存全尺寸照片
如果你提供了一个存储文件的地方,Android相机应用就可以存储全尺寸的照片。你必须提供一个完整的文件名来指定相机应用应该把照片保存在哪里。
一般来说,任何用户通过相机拍摄的照片都应该存储在设备的公共外部存储区域,这样他们就能被所有应用访问。一个合适的共享照片存储目录可以通过带有DIRECTORY_PICTURES参数的getExternalStoragePublicDirectory()函数获得。因为由该方法提供的目录是被所有应用所共享的,在目录内读或写分别要READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE的权限声明。写权限隐含了读权限,所以如果你需要写入外部目录,那么你只需要声明一个权限:
<manifest ...>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
...
</manifest>
然而,如果你希望保持这些照片是你应用私有的,那么你可以使用由getExternalFilesDir()提供的目录。在Android 4.3或更低版本的系统中,写入该目录也需要WRITE_EXTERNAL_STORAGE权限。从Android 4.4以后,这个权限就不在需要了。因为这个目录对其他应用来说是访问不到的,所以你可以通过使用maxSdkVersion字段来表明该权限声明只对低版本有效:
<manifest ...>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />
...
</manifest>
Note:
你存储在由getExternalFilesDir()所提供的目录内的文件,将会在用户删除你的应用时一起被删除。
一旦你决定了文件存储的目录,你需要创建一个不容易重名的文件名。你可能也希望在成员变量中存储路径名,以备今后使用。这里是一个方法的例子,它通过时间戳为一个新照片返回一个唯一的文件名:
String mCurrentPhotoPath; private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
); // Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = "file:" + image.getAbsolutePath();
return image;
}
通过这种方法为照片创建了文件,现在你可以像下面这样创建并激活Intent:
static final in REQUEST_TAKE_PHOTO = 1; private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
...
}
// Continue only if the File was successfully created
if (photoFile != null) {
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(photoFile));
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
}
五). 将照片添加至图库:
当你通过一个intent创建了一个照片,你应该知道照片放置在哪里,因为你指定了它需要存储在哪里。对其他任何应用来说,可能最简单的让你照片可访问的方法就是让它可被系统的媒体提供程序(Media Provider)可被访问。
Note:
如果你把文件存储在了由getExternalFilesDir()提供的路径,那么此时媒体扫描器
下面的方法证明了如何激活系统的媒体扫描器将你的照片添加至照片提供程序的数据库,使它对Android图库应用和其它应用来说是可以访问的。
private void galleryAddPic() {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(mCurrentPhotoPath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
this.sendBroadcast(mediaScanIntent);
}
六). 解码缩放图像
管理多个全尺寸图像对于有限的存储空间来说是很复杂的。如果你发现你的应用在显示了几幅图片后就用尽了存储,那么你可以通过将JPEG延展到一个记忆数组里面,它将图片缩放至目标View的尺寸,这样可以大幅减小使用的动态堆内存。下面的代码展示了这一技术:
private void setPic() {
// Get the dimensions of the View
int targetW = mImageView.getWidth();
int targetH = mImageView.getHeight(); // Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight; // Determine how much to scale down the image
int scaleFactor = Math.min(photoW/targetW, photoH/targetH); // Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true; Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
mImageView.setImageBitmap(bitmap);
}
【Android Developers Training】 48. 轻松拍摄照片的更多相关文章
- 【Android Developers Training】 52. 打印照片
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 47. 序言:拍摄照片
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 51. 序言:打印内容
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 49. 轻松录制视频
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 56. 更效率地加载大图片
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 55. 序言:高效显示位图
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 50. 控制相机
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 33. 接收来自其它应用的简单数据
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 29. 从Activity获得结果
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
随机推荐
- Asp.Net Core 中获取应用程序物理路径(Getting the Web Root Path and the Content Root Path in ASP.NET Core)
如果要得到传统的ASP.Net应用程序中的相对路径或虚拟路径对应的服务器物理路径,只需要使用使用Server.MapPath()方法来取得Asp.Net根目录的物理路径,如下所示: // Classi ...
- spring boot无法启动,或者正常启动之后无法访问报404的解决办法
以前用spring boot都是用idea的自动创建,或者是用的Jhipster创建的,就没有深究怎么去搭建.但是今天晚上心血来潮,想自己搭一个demo来整合一些技术,于是就花一点时间来手动搭.因为今 ...
- jenkins 集成钉钉机器人
最早做Jenkins发布完成以后通过邮件发送信息通知相关的联系人,发现邮件会受限于大家接收的设置,导致不能及时的看到相关的发布内容,公司使用钉钉做为公司内部的通讯工具,所以想通过Jenkins发布完成 ...
- Memcached和Redis简介
前言: 目前比较流行的缓存技术无疑是Memcached和Redis,两套缓存技术有着诸多的相似之处,但又具备大量的显著差异,作为新生的方案,Redis被视为首选,但是有些场景Memcached发挥的作 ...
- 使用cnpm搭建私有NPM仓库 发布npm包
关于如何使用cnpm搭建私有的npm仓库看这里→ http://blog.fens.me/nodejs-cnpm-npm/ 我本人还没有机会真正实践操作过,公司的npm仓库是我老大搭建的,我这里仅仅记 ...
- MySQL数据库安全策略
1. 删除所有MySQL中的用户(包括root用户): mysql> delete from mysql.user root可以保留,然后修改为其他用户 2. 为管理员root用户设置密码 : ...
- 2-SAT算法
参考blog 参考论文 参考论文 题目 & 题解 裸2-SAT poj3683 poj3207 poj3678 poj3648 2-SAT + 二分法 poj2723 poj2749 hdu3 ...
- C语言集成开发环境vs2017的使用技巧之修改快捷键
首先这里是说编辑C语言内容,其次开发环境是vs2017(全称:visual studio 2017).像这个开发环境体积大,但你安装的时候不要安装到C盘,然后安装的时候选择模块,比如你不开发网站,就先 ...
- Dubbo源码分析系列---服务的发布
摘要: 通过解析配置文件,将xml定义的Bean解析并实例化,(涉及重要的类:ServiceBean.RegistryConfig[注册中心配置].ProtocolConfig[协议配置].Appli ...
- Hadoop 2.7 伪分布式环境搭建
1.安装环境 ①.一台Linux CentOS6.7 系统 hostname ipaddress subnet mask ...