注:本文翻译自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_STORAGEWRITE_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. 轻松拍摄照片的更多相关文章

  1. 【Android Developers Training】 52. 打印照片

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  2. 【Android Developers Training】 47. 序言:拍摄照片

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  3. 【Android Developers Training】 51. 序言:打印内容

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  4. 【Android Developers Training】 49. 轻松录制视频

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  5. 【Android Developers Training】 56. 更效率地加载大图片

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  6. 【Android Developers Training】 55. 序言:高效显示位图

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  7. 【Android Developers Training】 50. 控制相机

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  8. 【Android Developers Training】 33. 接收来自其它应用的简单数据

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  9. 【Android Developers Training】 29. 从Activity获得结果

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

随机推荐

  1. Android GreenDAO3.0——介绍

    引言 最近,学东西比较零散,各种知识混杂,于是记下学习记录,免得又忘了. 官方网址:http://greenrobot.org/greendao/documentation/introduction/ ...

  2. 谈一谈Java8的函数式编程(二) --Java8中的流

    流与集合    众所周知,日常开发与操作中涉及到集合的操作相当频繁,而java中对于集合的操作又是相当麻烦.这里你可能就有疑问了,我感觉平常开发的时候操作集合时不麻烦呀?那下面我们从一个例子说起. 计 ...

  3. 第 7 章 MySQL 数据库锁定机制

      前言: 为了保证数据的一致完整性,任何一个数据库都存在锁定机制.锁定机制的优劣直接应想到一个数据库系统的并发处理能力和性能,所以锁定机制的实现也就成为了各种数据库的核心技术之一.本章将对 MySQ ...

  4. C语言socket编程——linux环境

    先写一个服务器端的监听程序,功能室从客户端读取字符,接收到后告知客户端“I got your message: ”+收到的消息:server.c #include <stdio.h> #i ...

  5. python 基础篇 2

    三.对变量.对象与赋值的浅析 1.不记住就完蛋了 1.1 记住:一切数据都是对象 1.2 记住:一切变量都是对数据对象的一个引用 1.3 分析:python内部的引用计数 sys.getrefcoun ...

  6. 安装lnmp集成环境

    具体配置看原文,不重新复述: 原文:https://lnmp.org/install.html 因为配置数据库主从,需要保持两台mysql数据库服务器的mysql版本号一致,所以又重新装了一次..重新 ...

  7. Zepto源码分析-event模块

    源码注释 // Zepto.js // (c) 2010-2015 Thomas Fuchs // Zepto.js may be freely distributed under the MIT l ...

  8. Hadoop的编译

    Hadoop2.4.0  重新编译 64  位本地库 原创作者:大鹏鸟 时间:2014-07-28 环境:虚拟机 VirtualBox,操作系统 64 位 CentOS 6.4 下载重新编译需要的软件 ...

  9. Linux命令不熟悉(记录)

    1.回到上一次操作的目录 cd - 2.rz打开上传文件 rz 3.下载某个文件 wget httpdownload 4.根据名字查找文件 find / -name mysql 5.通配符删除 rm ...

  10. Visual Studio Code 使用心得

    Visual Studio Code 使用心得 最好用的跨平台编辑器,没有之一! 修改编辑器的显示语言 起因:vsCode又升级了(1.13.0),重启之后发现熟悉的中文菜单没有了,而且设置文件 se ...