Android ACTION_IMAGE_CAPTURE意图

我们正尝试使用本机相机应用程序让用户拍摄一张新照片。 它工作得很好,如果我们EXTRA_OUTPUT extra并返回小的位图图像。 但是,如果我们在启动之前将putExtra(EXTRA_OUTPUT,...)放在了意图上,则一切正常,直到您尝试点击相机应用中的“确定”button。 “确定”button什么都不做。 相机应用程序保持打开状态,无法locking。 我们可以取消它,但文件永远不会被写入。 我们要做什么才能让ACTION_IMAGE_CAPTURE将拍摄的照片写入文件?

编辑:这是通过MediaStore.ACTION_IMAGE_CAPTURE意图完成的,只是要清楚

这是在一些版本的Android中有据可查的错误 。 也就是说,在谷歌体验Android的构build,图像捕获不起作用的文件。 我通常使用的是类似于公用事业类的东西。

 public boolean hasImageCaptureBug() { // list of known devices that have the bug ArrayList<String> devices = new ArrayList<String>(); devices.add("android-devphone1/dream_devphone/dream"); devices.add("generic/sdk/generic"); devices.add("vodafone/vfpioneer/sapphire"); devices.add("tmobile/kila/dream"); devices.add("verizon/voles/sholes"); devices.add("google_ion/google_ion/sapphire"); return devices.contains(android.os.Build.BRAND + "/" + android.os.Build.PRODUCT + "/" + android.os.Build.DEVICE); } 

那么当我启动图像捕捉,我创build一个检查错误的意图。

 Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); if (hasImageCaptureBug()) { i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File("/sdcard/tmp"))); } else { i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); } startActivityForResult(i, mRequestCode); 

然后在我返回的活动中,我根据设备做不同的事情。

 protected void onActivityResult(int requestCode, int resultCode, Intent intent) { switch (requestCode) { case GlobalConstants.IMAGE_CAPTURE: Uri u; if (hasImageCaptureBug()) { File fi = new File("/sdcard/tmp"); try { u = Uri.parse(android.provider.MediaStore.Images.Media.insertImage(getContentResolver(), fi.getAbsolutePath(), null, null)); if (!fi.delete()) { Log.i("logMarker", "Failed to delete " + fi); } } catch (FileNotFoundException e) { e.printStackTrace(); } } else { u = intent.getData(); } } 

这节省了你不得不写一个新的相机应用程序,但这个代码也不是很好。 大问题是

  1. 你从来没有从错误的设备得到全尺寸的图像。 您将得到插入到图像内容提供程序中的512像素宽的图片。 在没有bug的设备上,一切都可以作为文件,你会得到一个很大的正常图片。

  2. 你必须保持清单。 按照书面的说法,设备可能会被安装bug的android版本(比如cyanogenmod的版本 )刷新。 如果发生这种情况,你的代码将崩溃。 修复是使用整个设备指纹。

我知道这已经被回答了,但是我知道很多人对此感到沮丧,所以我要添加一条评论。

我在Nexus One上遇到了同样的问题。 这是相机应用程序启动之前,磁盘上不存在的文件。 因此,我确保在启动相机应用程序之前存在的文件。 以下是我使用的一些示例代码:

 String storageState = Environment.getExternalStorageState(); if(storageState.equals(Environment.MEDIA_MOUNTED)) { String path = Environment.getExternalStorageDirectory().getName() + File.separatorChar + "Android/data/" + MainActivity.this.getPackageName() + "/files/" + md5(upc) + ".jpg"; _photoFile = new File(path); try { if(_photoFile.exists() == false) { _photoFile.getParentFile().mkdirs(); _photoFile.createNewFile(); } } catch (IOException e) { Log.e(TAG, "Could not create file.", e); } Log.i(TAG, path); _fileUri = Uri.fromFile(_photoFile); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE ); intent.putExtra( MediaStore.EXTRA_OUTPUT, _fileUri); startActivityForResult(intent, TAKE_PICTURE); } else { new AlertDialog.Builder(MainActivity.this) .setMessage("External Storeage (SD Card) is required.\n\nCurrent state: " + storageState) .setCancelable(true).create().show(); } 

我首先使用MD5哈希创build一个独特的(有些)文件名,并将其放入适当的文件夹中。 然后我检查它是否存在(不应该,但它的好的做法是检查)。 如果它不存在,我得到父目录(一个文件夹),并创build文件夹层次结构(因此,如果文件所在位置的文件夹不存在,它们将在此行之后)。我创build文件,一旦创build文件,我得到Uri并将其传递给intent,然后OKbutton按预期工作,并且都是黄金的。

现在,当相机应用程序上按下“确定”button时,文件将出现在给定位置。 在这个例子中,它将是/sdcard/Android/data/com.example.myapp/files/234asdioue23498ad.jpg

没有必要复制上面发布的“onActivityResult”文件。

我已经经历了许多照片捕捉策略,似乎总是有一个案例,一个平台或某些设备,其中一些或全部上述策略将以意想不到的方式失败。 我能够find一个策略,使用下面的URI生成代码,似乎在大多数情况下,如果不是所有的情况下工作。

 mPhotoUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new ContentValues()); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, mPhotoUri); startActivityForResult(intent,CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE_CONTENT_RESOLVER); 

为了进一步促进讨论并帮助新手,我创build了一个示例/testing应用程序,展示了几种不同的照片捕捉实施策略。 其他实现的贡献肯定会被鼓励添加到讨论中。

https://github.com/deepwinter/AndroidCameraTester

我有相同的问题,相机应用程序中的确定button什么都没有,在模拟器和nexus之一。

MediaStore.EXTRA_OUTPUT中指定一个没有空白,没有特殊字符的安全文件名之后,问题就消失了。另外,如果你指定的文件驻留在尚未创build的目录中,则必须先创build它。 相机应用程序不会为你做mkdir。

您描述的工作stream程应该按照您所描述的工作。 如果您能够向我们展示围绕创buildIntent的代码,可能会有所帮助。 一般来说,下面的模式应该让你做你想做的事情。

 private void saveFullImage() { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); File file = new File(Environment.getExternalStorageDirectory(), "test.jpg"); outputFileUri = Uri.fromFile(file); intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri); startActivityForResult(intent, TAKE_PICTURE); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if ((requestCode == TAKE_PICTURE) && (resultCode == Activity.RESULT_OK)) { // Check if the result includes a thumbnail Bitmap if (data == null) { // TODO Do something with the full image stored // in outputFileUri. Perhaps copying it to the app folder } } } 

请注意, 相机活动将创build和保存文件,而实际上它并不是应用程序的一部分,所以它不会具有对应用程序文件夹的写入权限。 要将文件保存到您的应用程序文件夹,请在SD卡上创build一个临时文件,并将其移至onActivityResult处理程序中的应用程序文件夹。

为了跟上Yenchi上面的评论,如果相机应用程序不能写入相关目录,OKbutton也不会执行任何操作。

这意味着你不能在只能由你的应用程序写入的地方创build文件(例如, getCacheDir())下的东西getExternalFilesDir() 。然而, getExternalFilesDir()下的东西应该可以工作。

如果相机应用程序无法写入指定的EXTRA_OUTPUTpath,则会向日志打印错误消息,但是我没有find它。

让相机写入SD卡,但保留在画廊的应用程序,我用这个新的相册:

  File imageDirectory = new File("/sdcard/signifio"); String path = imageDirectory.toString().toLowerCase(); String name = imageDirectory.getName().toLowerCase(); ContentValues values = new ContentValues(); values.put(Media.TITLE, "Image"); values.put(Images.Media.BUCKET_ID, path.hashCode()); values.put(Images.Media.BUCKET_DISPLAY_NAME,name); values.put(Images.Media.MIME_TYPE, "image/jpeg"); values.put(Media.DESCRIPTION, "Image capture by camera"); values.put("_data", "/sdcard/signifio/1111.jpg"); uri = getContentResolver().insert( Media.EXTERNAL_CONTENT_URI , values); Intent i = new Intent("android.media.action.IMAGE_CAPTURE"); i.putExtra(MediaStore.EXTRA_OUTPUT, uri); startActivityForResult(i, 0); 

请注意,您将需要每次生成一个唯一的文件名,并replace我写的1111.jpg。 这是用nexustesting的。 uri是在私有类中声明的,所以在活动结果上,我能够从uri加载图像到imageView,以便在需要时进行预览。

我build议你按照Android培训岗位捕捉照片。 他们举例说明如何拍摄小照片和大照片。 您也可以从这里下载源代码

我有同样的问题,我解决了以下问题:

问题是,当你指定一个文件,只有你的应用程序有权访问(例如通过调用getFileStreamPath("file");

这就是为什么我只是确保给定的文件真的存在,每个人都有写入权限。

 Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); File outFile = getFileStreamPath(Config.IMAGE_FILENAME); outFile.createNewFile(); outFile.setWritable(true, false); intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT,Uri.fromFile(outFile)); startActivityForResult(intent, 2); 

这样,相机应用程序具有写入访问给定的Uri和确定button工作正常:)

用Activity Result Code解决这个问题很简单,试试这个方法

 if (reqCode == RECORD_VIDEO) { if(resCode == RESULT_OK) { if (uri != null) { compress(); } } else if(resCode == RESULT_CANCELED && data!=null){ Toast.makeText(MainActivity.this,"No Video Recorded",Toast.LENGTH_SHORT).show(); } } 

我创build了一个简单的库,它可以pipe理从不同来源(图库,照相机)中select图像,也可以将它保存到某个位置(SD卡或内存)并返回图像,请自由使用并改进它 – Android-ImageChooser 。

Praveen指出,该文件需要由相机写入。

在我的用法,我想存储在内部存储的文件。 我是这样做的:

 Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (i.resolveActivity(getPackageManager()!=null)){ try{ cacheFile = createTempFile("img",".jpg",getCacheDir()); cacheFile.setWritavle(true,false); }catch(IOException e){} if(cacheFile != null){ i.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(cacheFile)); startActivityForResult(i,REQUEST_IMAGE_CAPTURE); } } 

这里cacheFile是一个全局文件,用于引用写入的文件。 然后在结果方法中返回的意图是空的。 那么处理意图的方法如下所示:

 protected void onActivityResult(int requestCode,int resultCode,Intent data){ if(requestCode != RESULT_OK){ return; } if(requestCode == REQUEST_IMAGE_CAPTURE){ try{ File output = getImageFile(); if(output != null && cacheFile != null){ copyFile(cacheFile,output); //Process image file stored at output cacheFile.delete(); cacheFile=null; } }catch(IOException e){} } } 

这里的getImageFile()是一个实用的方法来命名和创build图像应该存储在其中的文件, copyFile()是一个复制文件的方法。

你可以使用这个代码

 private Intent getCameraIntent() { PackageManager packageManager = mContext.getPackageManager(); List<ApplicationInfo> list = packageManager.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES); Intent main = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); List<ResolveInfo> launchables = packageManager.queryIntentActivities(main, 0); if (launchables.size() == 1) return packageManager.getLaunchIntentForPackage(launchables.get(0).activityInfo.packageName); else for (int n = 0; n < list.size(); n++) { if ((list.get(n).flags & ApplicationInfo.FLAG_SYSTEM) == 1) { Log.d("TAG", "Installed Applications : " + list.get(n).loadLabel(packageManager).toString()); Log.d("TAG", "package name : " + list.get(n).packageName); String defaultCameraPackage = list.get(n).packageName; if (launchables.size() > 1) for (int i = 0; i < launchables.size(); i++) { if (defaultCameraPackage.equals(launchables.get(i).activityInfo.packageName)) { return packageManager.getLaunchIntentForPackage(defaultCameraPackage); } } } } return null; } 
 protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_CANCELED) { //do not process data, I use return; to resume activity calling camera intent enter code here } }