【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 ...
随机推荐
- Archive for required library:xxxxx/spring-beans-3.2.4.RELEASE.jar in project XXXXX cannot be read or is not a valid ZIP file
今天在导入maven项目的时候在problems视图中报错: Archive for required library:xxxxx/spring-beans-3.2.4.RELEASE.jar in ...
- 【WPF】学习笔记(三)——这个家伙跟电子签名板有个约定
这篇博客依旧是以电子签名板为基础而展开的,主要是对前文([WPF]学习笔记(一)--做一个简单的电子签名板)存在的部分问题进行解释,以及部分小功能的添加.由于这篇博客是建立在学习笔记一的基础上的,所以 ...
- Collection<E>、Iterable<T>和Iterator<E>接口
Collection接口 public interface Collection<E>extends Iterable<E> Collection接口主要包含以下方法: Ite ...
- 镜像命名的最佳实践 - 每天5分钟玩转 Docker 容器技术(18)
我们已经学会构建自己的镜像了.接下来的问题是如何在多个 Docker Host 上使用镜像. 这里有几种可用的方法: 用相同的 Dockerfile 在其他 host 构建镜像. 将镜像上传到公共 R ...
- html学习笔记 - 列表
<!-- 无序列表 --> <ul type = square> <li><a href="https://www.baidu.com"& ...
- Memcached和Redis简介
前言: 目前比较流行的缓存技术无疑是Memcached和Redis,两套缓存技术有着诸多的相似之处,但又具备大量的显著差异,作为新生的方案,Redis被视为首选,但是有些场景Memcached发挥的作 ...
- LINQ之LINQ to Objects(上)
LINQ概述 LINQ,语言集成查询(Language Integrated Query),它允许使用C#或VB代码以查询数据库相同的方式来操作不同的数据源. 1.LINQ体系结构 从上图可以看出,L ...
- Http学习之使用HttpURLConnection发送post和get请求(2)
接上节Http学习之使用HttpURLConnection发送post和get请求 本节深入学习post请求. 上 节说道,post请求的OutputStream实际上不是网络流,而是写入内存,在ge ...
- Not supported by Zabbix Agent & zabbix agent重装
zabbix服务器显示一些监控项不起效,提示错误[Not supported by Zabbix Agent], 最后定位为zabbix客户端版本过低. Not supported by Zabbix ...
- mysql之 binlog维护详细解析(开启、binlog相关参数作用、mysqlbinlog解读、binlog删除)
binary log 作用:主要实现三个重要的功能:用于复制,用于恢复,用于审计.binary log 相关参数:log_bin设置此参数表示启用binlog功能,并指定路径名称log_bin_ind ...