相机意图捕获的图片文件在onActivityResult中暂时为空
Picture file captured with camera intent empty for a while in onActivityResult
我在尝试通过 intent 拍照时遇到了一个非常奇怪的错误。
Activity 代码(稍微简化):
private void startCapture() throws IOException {
// Create output file
final File photoFile = makePhotoFile();
_photoPath = photoFile.getAbsolutePath();
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
/* IMPORTANT NOTE TO READERS
* As of Android N (which went out shortly after I posted this question),
* you cannot use Uri.fromFile this way anymore.
* You should use a FileProvider. */
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
if (cameraIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(cameraIntent, REQUEST_CODE_IMAGE_CAPTURE);
}
else {
deleteCurrentPhoto();
}
}
private File makePhotoFile() throws IOException {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(new Date());
String imageFileName = "MyPhoto_" + timeStamp + "_";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
return File.createTempFile(imageFileName, ".jpg", storageDir);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_CODE_IMAGE_CAPTURE) {
if(resultCode == RESULT_OK) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
final byte[] buffer = new byte[2048];
int read;
byte[] photoBytes;
try(FileInputStream fis = new FileInputStream(_photoPath)) {
for(int i=0; i<10; i++) { // Always working after first iteration though
if( (read = fis.read(buffer)) <= 0) {
// Why does this get printed once ??
Log.w("my.package.my.app", "Empty for now...");
}
else {
Log.w("my.package.my.app", "Working now !");
bos.write(buffer, 0, read);
break;
}
}
while((read = fis.read(buffer)) >= 0) {
bos.write(buffer, 0, read);
}
photoBytes = bos.toByteArray();
} // Catch clauses removed for simplicity
// Everything working OK after that (photoBytes decodes fine with the BitmapFactory)
}
}
}
并且日志输出:
03-01 16:32:34.139 23414-23414/my.package.my.app W/my.package.my.app:
Empty for now... 03-01 16:32:34.139 23414-23414/my.package.my.app
W/my.package.my.app: Working now !
可以看到,在拍照后的onActivityResult中,第一次调用FileInputStream.read时文件是空的...然后就可以正确读取了!
我以为当相机意图 returns 调用 activity 时,文件已经写入。有什么延迟吗?我也很惊讶地看到它总是在 for 循环中恰好一次迭代后工作。
注意,如果我在onActivityResult的开头打断点,会稍微延迟执行,一切正常(第一次尝试正确读取文件)。
我在 Android 6.0.1 下使用普通 Nexus 6P 和普通相机应用程序。
重要编辑:至于 Android N,您应该使用 FileProvider
而不是像我之前那样使用 Uri.fromFile
。参见 this blog post and these explanations from the Android team。
尚未创建该文件。删除 File.createTempFile()
.
您唯一需要的是文件名。文件路径。相机应用程序将自行创建文件。所以改变你的功能来创建新的文件名。例如。 new File(storageDir, imageFileName + ".jpg")
我在尝试通过 intent 拍照时遇到了一个非常奇怪的错误。 Activity 代码(稍微简化):
private void startCapture() throws IOException {
// Create output file
final File photoFile = makePhotoFile();
_photoPath = photoFile.getAbsolutePath();
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
/* IMPORTANT NOTE TO READERS
* As of Android N (which went out shortly after I posted this question),
* you cannot use Uri.fromFile this way anymore.
* You should use a FileProvider. */
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
if (cameraIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(cameraIntent, REQUEST_CODE_IMAGE_CAPTURE);
}
else {
deleteCurrentPhoto();
}
}
private File makePhotoFile() throws IOException {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(new Date());
String imageFileName = "MyPhoto_" + timeStamp + "_";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
return File.createTempFile(imageFileName, ".jpg", storageDir);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_CODE_IMAGE_CAPTURE) {
if(resultCode == RESULT_OK) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
final byte[] buffer = new byte[2048];
int read;
byte[] photoBytes;
try(FileInputStream fis = new FileInputStream(_photoPath)) {
for(int i=0; i<10; i++) { // Always working after first iteration though
if( (read = fis.read(buffer)) <= 0) {
// Why does this get printed once ??
Log.w("my.package.my.app", "Empty for now...");
}
else {
Log.w("my.package.my.app", "Working now !");
bos.write(buffer, 0, read);
break;
}
}
while((read = fis.read(buffer)) >= 0) {
bos.write(buffer, 0, read);
}
photoBytes = bos.toByteArray();
} // Catch clauses removed for simplicity
// Everything working OK after that (photoBytes decodes fine with the BitmapFactory)
}
}
}
并且日志输出:
03-01 16:32:34.139 23414-23414/my.package.my.app W/my.package.my.app: Empty for now... 03-01 16:32:34.139 23414-23414/my.package.my.app W/my.package.my.app: Working now !
可以看到,在拍照后的onActivityResult中,第一次调用FileInputStream.read时文件是空的...然后就可以正确读取了! 我以为当相机意图 returns 调用 activity 时,文件已经写入。有什么延迟吗?我也很惊讶地看到它总是在 for 循环中恰好一次迭代后工作。
注意,如果我在onActivityResult的开头打断点,会稍微延迟执行,一切正常(第一次尝试正确读取文件)。
我在 Android 6.0.1 下使用普通 Nexus 6P 和普通相机应用程序。
重要编辑:至于 Android N,您应该使用 FileProvider
而不是像我之前那样使用 Uri.fromFile
。参见 this blog post and these explanations from the Android team。
尚未创建该文件。删除 File.createTempFile()
.
您唯一需要的是文件名。文件路径。相机应用程序将自行创建文件。所以改变你的功能来创建新的文件名。例如。 new File(storageDir, imageFileName + ".jpg")