26

这似乎是世界上最简单的事情:使用默认的相机活动在您的 Android 应用程序中拍照。然而,在 StackOverflow 和网络上的几篇文章中涵盖了许多陷阱,例如,Null Intent 被传回,图片的方向不正确或 OutOfMemoryErrors。

我正在寻找一种解决方案,让我能够

  1. 通过相机意图启动相机活动,
  2. 检索照片的 Uri,以及
  3. 检索照片的正确方向。

此外,我想尽可能避免设备配置(制造商、型号、操作系统版本)特定的实现。所以我想知道:实现这一目标的最佳方法是什么?

4

4 回答 4

23

更新:2014 年 1 月 2 日: 我非常努力地避免根据设备制造商实施不同的策略。不幸的是,我没有绕过它。经过数百篇帖子并与几位开发人员交谈,没有人找到适用于所有设备的解决方案,而无需实现设备制造商特定的代码。

在我在 StackOverflow 上发布我的解决方案后,一些开发人员要求我在 github 上发布我的代码。所以现在是:github上的AndroidCameraUtil

该代码已在 Android API-Level >= 8 的各种设备上成功测试。有关完整列表,请参阅 github 上的自述文件。

CameraIntentHelperActivity提供了主要功能,下面也会更详细地介绍。

调用默认相机活动:

  • 对于三星和索尼设备:我使用 startActivityForResult 的方法调用来调用相机活动。我只设置了常量 CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE。我没有设置任何其他意图附加功能。
  • 对于所有其他设备:我像以前一样使用对 startActivityForResult 的方法调用来调用相机活动。但是,这一次,我另外设置了额外的 MediaStore.EXTRA_OUTPUT 意图并提供了一个 URI,我希望将图像存储在其中。

在这两种情况下,我都记得相机活动开始的时间。


关于相机活动结果:

  1. Mediastore:首先,我尝试读取从 MediaStore 捕获的照片。在 MediaStore 内容上使用 mangedQuery,我检索正在拍摄的最新图像,以及它的方向属性和它的时间戳。如果我找到一张图像并且在调用相机意图之前没有拍摄,那么它就是我正在寻找的图像。否则,我会忽略结果并尝试以下方法之一。
  2. Intent extra:其次,我尝试从返回意图的 intent.getData() 中获取图像 Uri。如果这也不成功,我继续第 3 步。
  3. 默认照片 Uri:如果上述所有步骤都不起作用,我使用传递给相机活动的图像 Uri。

此时,我检索了传递给 UploadPhotoActivity 的照片 Uri 及其方向。


图像处理

请仔细看看我的 BitmapHelper 课程。它基于该教程中详细描述的代码。

此外,如果需要,shrinkBitmap 方法还会根据之前提取的方向信息旋转图像。


我希望这对你们中的一些人有所帮助。

于 2013-04-30T08:10:22.170 回答
0

我已经使用 Sony Xperia Go、Samsung Galaxy SII、Samsung Galaxy SIII mini 和 Samsung Galaxy Y 测试了此代码,它适用于所有设备!

但是在 LG E400 (2.3.6) 上它不起作用,您在图库中获得了两张图片。所以我在 void startCameraIntent() 中添加了manufacturer.contains("lge") 并解决了这个问题。

if(!(manufacturer.contains("samsung")) && !(manufacturer.contains("sony")) && !(manufacturer.contains("lge"))) {
    String filename = System.currentTimeMillis() + ".jpg";
    ContentValues values = new ContentValues();
    values.put(MediaStore.Images.Media.TITLE, filename);
    cameraPicUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, cameraPicUri);
}
于 2013-06-19T07:57:43.203 回答
0

在带有 CM 10.1 的 Galaxy S3 上,我在 BitmapHelper 中得到一个空指针异常:

bm = BitmapFactory.decodeFileDescriptor(fileDescriptor.getFileDescriptor(), null, options);

随后我的 UploadPhotoActivity 在以下位置失败:

    try {
        photo = BitmapHelper.readBitmap(this, cameraPicUri);
        if (photo != null) {
            photo = BitmapHelper.shrinkBitmap(photo, 600, rotateXDegrees);
            thumbnail = BitmapHelper.shrinkBitmap(photo, 100);
            ImageView imageView = (ImageView) findViewById(R.id.sustainable_action_photo);
            imageView.setImageBitmap(photo);                
        } else {
            Log.e(TAG,"IMAGE ERROR 1");
        }
    } catch (Exception e) {
            Log.e(TAG,"IMAGE ERROR 2");
        e.printStackTrace();
    }

在第二个日志(图像错误 2)。几次尝试后,我的相机坏了,出现“无法连接到相机”错误。

在nexus 7上进行了测试,效果很好。

编辑:缩小到这个:

fileDescriptor = context.getContentResolver().openAssetFileDescriptor(selectedImage, "r");

尽管 selectedImage 包含以下内容:

file:///storage/emulated/0/DCIM/Camera/IMG_20131023_183343.jpg

fileDescriptor 返回 FileNotFoundException。我检查了文件系统,图像没有保存在这个位置。TakePhotoActivity 中的 cameraPicUri 指向一个不存在的图像。我目前正在检查哪里出了问题。

Edit2:我发现了错误:由于设备是三星设备,并告诉应用它是三星设备,因此应用了您的三星特定修复程序。不过,Cyanogenmod 不需要这些修复,最终代码会中断。一旦你删除

(manufacturer.contains("samsung")) &&

有用。由于这是一个自定义 ROM,因此您当然无法为此计划。我正在尝试找出一种方法来检测设备是否正在运行 cyanogenmod,然后将其包含在您的代码中。

感谢您的相机修复!

Edit3:我通过将您的代码更改为,将它修复为在 Galaxy S3 上的 Cyanogenmod 上运行: 嗯,现在它有时可以工作,有时不能。奇怪的。

if (getPackageManager().hasSystemFeature("com.cyanogenmod.android") || (!(manufacturer.contains("samsung")) && !(manufacturer.contains("sony")) && !(manufacturer.contains(" lge"))))

于 2013-10-23T16:06:23.217 回答
0

我在使用 Sony Xperia Z5 时遇到了一些问题。

我添加了这个,它变得好多了。

if (buildType.contains("sony")&& buildDevice.contains("e5823")) {
                setPreDefinedCameraUri = true;}

但是在 22 次中有 4 次重新启动了相机,并且一次重新启动了两次。由于每次测试,我都重新启动了应用程序。有什么办法可以解决这个问题还是我接受这个结果?

问题是,如果相机重新启动,我可以按两次后退按钮并繁荣,图像在我的 Imageview 中并保存

于 2016-02-05T14:28:12.547 回答