本文共 6126 字,大约阅读时间需要 20 分钟。
本课将告诉您如何通过将工作委派给设备上的其他相机应用来捕获照片。(如果您更愿意构建自己的相机功能,请参阅控制相机。)
假设您正在实施通过运行客户端应用的设备拍摄的天空图片来制作全球天气图的人群源天气服务。集成照片只是应用程序的一小部分。你想用最少的手段拍照,而不是重新发明相机。令人高兴的是,大多数基于Android的设备已经安装了至少一个摄像头应用程序。在本课中,您将学习如何为您拍摄照片。
如果您的应用程序的基本功能正在拍摄照片,请将其在Google Play上的可见度限制为拥有相机的设备。要宣传您的应用程序依赖于使用相机,请在清单文件中添加一个标签: <uses-feature>
...
如果您的应用程序使用,但不需要相机才能运行,而是设置android:required为false。这样做,Google Play将允许没有摄像头的设备下载您的应用程序。这是你的责任,通过调用在运行时检查相机的可用性hasSystemFeature(PackageManager.FEATURE_CAMERA)。如果相机不可用,则应该禁用相机功能。
将操作委托给其他应用程序的Android方法是调用Intent描述你想要完成的操作。该过程涉及三部分: Intent自身,启动外部的调用Activity以及焦点返回到活动时处理图像数据的一些代码。
这是一个调用意图捕获照片的函数。
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()返回可处理意图的第一个活动组件。执行此检查非常重要,因为如果您startActivityForResult()使用无应用程序可以处理的意图进行调用,则您的应用程序将崩溃。所以只要结果不为空,就可以安全使用意图。
如果拍摄照片的简单技巧不是应用程序雄心壮志的顶点,那么您可能希望从相机应用程序中获取图像并对其进行处理。
Android相机应用程序编码在返回的照片Intent 传送到onActivityResult()一个小Bitmap的演员,下键"data"。以下代码检索此图像并将其显示在ImageView。
@Overrideprotected 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); }}
注意:这个缩略图"data"可能对图标有用,但不是更多。处理全尺寸图像需要更多工作。
如果您为其保存文件,Android Camera应用程序会保存一张全尺寸的照片。您必须提供相机应用程序应该保存照片的完全限定文件名。
通常,用户使用设备摄像头拍摄的任何照片都应该保存在公共外部存储设备中,以便所有应用均可访问。共享照片正确的目录是由提供getExternalStoragePublicDirectory()与DIRECTORY_PICTURES争论。由于此方法提供的目录在所有应用程序之间共享,因此读取和写入目录需要使用 权限READ_EXTERNAL_STORAGE和 WRITE_EXTERNAL_STORAGE权限。写入权限隐式允许读取,因此如果您需要写入外部存储器,则只需要请求一个权限:
...
但是,如果您希望照片仅保留在您的应用中,则可以使用由其提供的目录getExternalFilesDir()。在Android 4.3及更低版本上,写入此目录也需要 WRITE_EXTERNAL_STORAGE权限。从Android 4.4开始,由于该目录不能被其他应用程序访问,因此不再需要该权限,因此您可以通过添加maxSdkVersion 属性来声明仅在较低版本的Android上请求权限:
...
注意:当用户卸载您的应用程序时,您保存在目录提供的文件中 getExternalFilesDir()或将 getFilesDir()被删除的文件。
一旦你决定了该文件的目录,你需要创建一个防冲突的文件名。您也可以将路径保存在成员变量中供以后使用。下面是一个方法中的示例解决方案,该方法使用日期时间戳为新照片返回唯一文件名:
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 = getExternalFilesDir(Environment.DIRECTORY_PICTURES); File image = File.createTempFile( imageFileName, /* prefix */ ".jpg", /* suffix */ storageDir /* directory */ ); // Save a file: path for use with ACTION_VIEW intents mCurrentPhotoPath = image.getAbsolutePath(); return image;}
通过这种方法可以为照片创建一个文件,现在可以Intent像这样创建和调用:
static final int 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) { Uri photoURI = FileProvider.getUriForFile(this, "com.example.android.fileprovider", photoFile); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO); } }}
注意:我们使用getUriForFile(Context, String, File)哪个返回一个content:// URI。对于更多针对Android 7.0(API级别24)及更高版本的应用,file://在包边界上传递URI会导致一个FileUriExposedException。因此,我们现在提出一种更通用的使用a存储图像的方法 FileProvider。
现在,你需要配置FileProvider。在您的应用清单中,向您的应用添加提供商:
... ...
确保当局字符串与第二个参数匹配getUriForFile(Context, String, File)。在提供者定义的元数据部分中,您可以看到提供者期望合格的路径被配置在专用资源文件中, RES / XML / file_paths.xml。以下是此特定示例所需的内容:
路径组件对应于getExternalFilesDir() 调用时返回的路径 Environment.DIRECTORY_PICTURES。确保您使用com.example.package.name应用的实际包名替换 。此外,请检查FileProvider您可以使用的路径说明符的详细说明 的文档external-path。
当您通过意图创建照片时,您应该知道您的图像所在的位置,因为您说过首先将其保存在哪里。对于其他人而言,让您的照片易于访问的最简单方法是让系统的媒体提供商访问它。
注意:如果您将照片保存到提供的目录中 getExternalFilesDir(),则媒体扫描程序无法访问这些文件,因为它们对您的应用程序是私人的。
以下示例方法演示了如何调用系统的媒体扫描器将照片添加到媒体提供程序的数据库,使其可在Android Gallery应用程序和其他应用程序中使用。
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扩展到已调整大小以匹配目标视图大小的内存阵列来显着减少使用的动态堆量。以下示例方法演示了这种技术。
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);}
Lastest Update:2018.04.17
QQ:94297366
微信打赏:
公众号推荐:
转载于:https://blog.51cto.com/4789781/2125841