相机结果代码和 RESULT_OK 不相等,仅在 nexus 5 (lollipop) 中相机意图后应用程序崩溃
camera result code and RESULT_OK unequal, app crashing after camera intent only in nexus 5 (lollipop)
同样的代码运行在其他设备中就像一个魅力,但在 Nexus 5(OS 版本 5.1.1)中无法 运行它。
当我在 nexus 5 中 运行 下面的代码时,我得到 NullPointerException,resultCode=0 的值和 [=40= 的值]=-1,因此我在 getActivityForResult 中的 if 条件不 运行.
而在其他设备(其他型号,如三星、htc 等)中,相同的代码 运行 毫无例外地像一个魅力和 resultCode=-1[=31= 的值] 和 RESULT_OK=-1,两个值都相同,所以 if 条件 运行s 以及我程序的其余部分。
JAVA 代码
mainActivity.java
public void callCamera() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
// start the image capture Intent
startActivityForResult(intent, 100);
Log.i("hello", "callCamera");
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.i("hello", "" + requestCode);
Log.i("hello", "" + resultCode);
Log.i("hello", "" + this.RESULT_OK);
if (requestCode == 100 && resultCode == RESULT_OK) {
// fileUri=data.getExtras().get("data");
photo = (Bitmap) data.getExtras().get("data");
//*selectedImage = data.getData();
//photo = (Bitmap) data.getExtras().get("data");
Log.i("hello","onActivityResult");
uploadImage();
}
}
LOGCAT 如果是 NEXUS 5
FATAL EXCEPTION: main Process: com.google.android.GoogleCamera, PID: 24887
java.lang.NullPointerException at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:187)
at com.google.common.base.Optional.of(Optional.java:84)
at com.android.camera.captureintent.state.StateSavingPicture.onEnter(StateSavingPicture.java:77)
at com.android.camera.captureintent.stateful.StateMachineImpl.jumpToState(StateMachineImpl.java:62)
at com.android.camera.captureintent.stateful.StateMachineImpl.processEvent(StateMachineImpl.java:110)
at com.android.camera.captureintent.state.StateOpeningCamera.onClick(StateOpeningCamera.java:307)
at android.view.View.performClick(View.java:4780)
at android.view.View$PerformClick.run(View.java:19866)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
从 callCamera() 方法中删除 intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
行,这将修复崩溃。就像您从 onActivityResult() 意图获取 uri 一样,该意图会将数据接收为 null,因为您在启动相机意图时在意图中放置了一个额外的 uri 值,这定义了您已经有一个文件 uri对于您的相机图像,您不想在 onActivityResult() 中使用数据意图,我还建议您删除 callCamera() 方法中使用的 fileuri 变量,因为它没有用。
所以您的 callCamera 方法应该如下所示:
public void callCamera() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 100);
}
/*** Created by wildcoder on 06/06/16.*/
import android.Manifest;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Intent;
import android.media.CameraProfile;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.widget.Toast;
public class FragmentVideoRecorder extends BaseFragment {
private Uri fileUri;
private static final int CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE = 200;
public static Activity ActivityContext = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityContext = getActivity();
}
/**
* @param parentDirectory Your folder name
*/
protected void startRecording(File parentDirectory) {
if (Utilities.isGranted(getActivity(), Manifest.permission.RECORD_AUDIO) && Utilities.isGranted(getActivity(), Manifest.permission.CAMERA)) {
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
// create a file to save the video
fileUri = getOutputMediaFileUri(parentDirectory);
// set the image file name
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
intent.putExtra(MediaStore.EXTRA_SIZE_LIMIT, 10000000);
// set the video image quality to high
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, CameraProfile.QUALITY_LOW);
// start the Video Capture Intent
startActivityForResult(intent, CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE);
} else {
Utilities.openAppSetting(ActivityContext);
}
}
/**
* @param contentResolver
* @param file to delete
*/
public void deleteFileFromMediaStore(final ContentResolver contentResolver, final File file) {
String canonicalPath;
try {
canonicalPath = file.getCanonicalPath();
} catch (IOException e) {
canonicalPath = file.getAbsolutePath();
}
final Uri uri = MediaStore.Files.getContentUri("external");
final int result = contentResolver.delete(uri,
MediaStore.Files.FileColumns.DATA + "=?", new String[]{canonicalPath});
if (result == 0) {
final String absolutePath = file.getAbsolutePath();
if (!absolutePath.equals(canonicalPath)) {
contentResolver.delete(uri,
MediaStore.Files.FileColumns.DATA + "=?", new String[]{absolutePath});
}
}
}
/**
* Create a file Uri for saving an image or video
*/
private Uri getOutputMediaFileUri(File parent) {
return Uri.fromFile(getOutputMediaFile(parent));
}
/**
* Create a File for saving an image or video
*/
private File getOutputMediaFile(File mediaStorageDir) {
// Check that the SDCard is mounted
// Create the storage directory(MyCameraVideo) if it does not exist
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Toast.makeText(ActivityContext, "Failed to create directory MyCameraVideo.",
Toast.LENGTH_LONG).show();
Log.d("MyCameraVideo", "Failed to create directory MyCameraVideo.");
return null;
}
}
File mediaFile = new File(mediaStorageDir, "intro_video.mp4");
if (mediaFile.exists()) {
deleteFileFromMediaStore(ActivityContext.getContentResolver(), mediaFile);
}
return mediaFile;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// After camera screen this code will excuted
if (requestCode == CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
// Video captured and saved to fileUri specified in the Intent
Toast.makeText(ActivityContext, "Video saved to: " + data.getData(), Toast.LENGTH_LONG).show();
} else if (resultCode == Activity.RESULT_CANCELED) {
// User cancelled the video capture
Toast.makeText(ActivityContext, "User cancelled the video capture.",
Toast.LENGTH_LONG).show();
} else {
// Video capture failed, advise user
Toast.makeText(ActivityContext, "Video capture failed.",
Toast.LENGTH_LONG).show();
}
}
}
}
确保在捕获视频后单击刻度线(在 Nexus 5 中为蓝色,Android 8)。只有在打勾之后,结果才设置为RESULT_OK。如果您单击任何其他按钮,则不会正确设置结果代码。
问题是 Android11 要求您使用 Fileprovider。解决方案:
[1] 确保使用 FileProvider 生成 fileUri,例如:
File outputDir = getExternalCacheDir();
File out = File.createTempFile("android_upload", ".jpg", outputDir);
fileUri = FileProvider.getUriForFile(this, "com.your.app.id.fileprovider", out);
(将 com.your.app.id 替换为您的应用程序 ID)。
[2] 添加到您的 AndroidManifest.xml:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.your.app.id.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_provider_paths"/>
</provider>
[3] 创建文件 res/xml/file_provider_paths.xml:
<paths>
<external-cache-path name="cache" path="/" />
</paths>
同样的代码运行在其他设备中就像一个魅力,但在 Nexus 5(OS 版本 5.1.1)中无法 运行它。
当我在 nexus 5 中 运行 下面的代码时,我得到 NullPointerException,resultCode=0 的值和 [=40= 的值]=-1,因此我在 getActivityForResult 中的 if 条件不 运行.
而在其他设备(其他型号,如三星、htc 等)中,相同的代码 运行 毫无例外地像一个魅力和 resultCode=-1[=31= 的值] 和 RESULT_OK=-1,两个值都相同,所以 if 条件 运行s 以及我程序的其余部分。
JAVA 代码 mainActivity.java
public void callCamera() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
// start the image capture Intent
startActivityForResult(intent, 100);
Log.i("hello", "callCamera");
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.i("hello", "" + requestCode);
Log.i("hello", "" + resultCode);
Log.i("hello", "" + this.RESULT_OK);
if (requestCode == 100 && resultCode == RESULT_OK) {
// fileUri=data.getExtras().get("data");
photo = (Bitmap) data.getExtras().get("data");
//*selectedImage = data.getData();
//photo = (Bitmap) data.getExtras().get("data");
Log.i("hello","onActivityResult");
uploadImage();
}
}
LOGCAT 如果是 NEXUS 5
FATAL EXCEPTION: main Process: com.google.android.GoogleCamera, PID: 24887
java.lang.NullPointerException at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:187)
at com.google.common.base.Optional.of(Optional.java:84)
at com.android.camera.captureintent.state.StateSavingPicture.onEnter(StateSavingPicture.java:77)
at com.android.camera.captureintent.stateful.StateMachineImpl.jumpToState(StateMachineImpl.java:62)
at com.android.camera.captureintent.stateful.StateMachineImpl.processEvent(StateMachineImpl.java:110)
at com.android.camera.captureintent.state.StateOpeningCamera.onClick(StateOpeningCamera.java:307)
at android.view.View.performClick(View.java:4780)
at android.view.View$PerformClick.run(View.java:19866)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
从 callCamera() 方法中删除 intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
行,这将修复崩溃。就像您从 onActivityResult() 意图获取 uri 一样,该意图会将数据接收为 null,因为您在启动相机意图时在意图中放置了一个额外的 uri 值,这定义了您已经有一个文件 uri对于您的相机图像,您不想在 onActivityResult() 中使用数据意图,我还建议您删除 callCamera() 方法中使用的 fileuri 变量,因为它没有用。
所以您的 callCamera 方法应该如下所示:
public void callCamera() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 100);
}
/*** Created by wildcoder on 06/06/16.*/
import android.Manifest;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Intent;
import android.media.CameraProfile;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.widget.Toast;
public class FragmentVideoRecorder extends BaseFragment {
private Uri fileUri;
private static final int CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE = 200;
public static Activity ActivityContext = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityContext = getActivity();
}
/**
* @param parentDirectory Your folder name
*/
protected void startRecording(File parentDirectory) {
if (Utilities.isGranted(getActivity(), Manifest.permission.RECORD_AUDIO) && Utilities.isGranted(getActivity(), Manifest.permission.CAMERA)) {
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
// create a file to save the video
fileUri = getOutputMediaFileUri(parentDirectory);
// set the image file name
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
intent.putExtra(MediaStore.EXTRA_SIZE_LIMIT, 10000000);
// set the video image quality to high
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, CameraProfile.QUALITY_LOW);
// start the Video Capture Intent
startActivityForResult(intent, CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE);
} else {
Utilities.openAppSetting(ActivityContext);
}
}
/**
* @param contentResolver
* @param file to delete
*/
public void deleteFileFromMediaStore(final ContentResolver contentResolver, final File file) {
String canonicalPath;
try {
canonicalPath = file.getCanonicalPath();
} catch (IOException e) {
canonicalPath = file.getAbsolutePath();
}
final Uri uri = MediaStore.Files.getContentUri("external");
final int result = contentResolver.delete(uri,
MediaStore.Files.FileColumns.DATA + "=?", new String[]{canonicalPath});
if (result == 0) {
final String absolutePath = file.getAbsolutePath();
if (!absolutePath.equals(canonicalPath)) {
contentResolver.delete(uri,
MediaStore.Files.FileColumns.DATA + "=?", new String[]{absolutePath});
}
}
}
/**
* Create a file Uri for saving an image or video
*/
private Uri getOutputMediaFileUri(File parent) {
return Uri.fromFile(getOutputMediaFile(parent));
}
/**
* Create a File for saving an image or video
*/
private File getOutputMediaFile(File mediaStorageDir) {
// Check that the SDCard is mounted
// Create the storage directory(MyCameraVideo) if it does not exist
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Toast.makeText(ActivityContext, "Failed to create directory MyCameraVideo.",
Toast.LENGTH_LONG).show();
Log.d("MyCameraVideo", "Failed to create directory MyCameraVideo.");
return null;
}
}
File mediaFile = new File(mediaStorageDir, "intro_video.mp4");
if (mediaFile.exists()) {
deleteFileFromMediaStore(ActivityContext.getContentResolver(), mediaFile);
}
return mediaFile;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// After camera screen this code will excuted
if (requestCode == CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
// Video captured and saved to fileUri specified in the Intent
Toast.makeText(ActivityContext, "Video saved to: " + data.getData(), Toast.LENGTH_LONG).show();
} else if (resultCode == Activity.RESULT_CANCELED) {
// User cancelled the video capture
Toast.makeText(ActivityContext, "User cancelled the video capture.",
Toast.LENGTH_LONG).show();
} else {
// Video capture failed, advise user
Toast.makeText(ActivityContext, "Video capture failed.",
Toast.LENGTH_LONG).show();
}
}
}
}
确保在捕获视频后单击刻度线(在 Nexus 5 中为蓝色,Android 8)。只有在打勾之后,结果才设置为RESULT_OK。如果您单击任何其他按钮,则不会正确设置结果代码。
问题是 Android11 要求您使用 Fileprovider。解决方案:
[1] 确保使用 FileProvider 生成 fileUri,例如:
File outputDir = getExternalCacheDir();
File out = File.createTempFile("android_upload", ".jpg", outputDir);
fileUri = FileProvider.getUriForFile(this, "com.your.app.id.fileprovider", out);
(将 com.your.app.id 替换为您的应用程序 ID)。
[2] 添加到您的 AndroidManifest.xml:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.your.app.id.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_provider_paths"/>
</provider>
[3] 创建文件 res/xml/file_provider_paths.xml:
<paths>
<external-cache-path name="cache" path="/" />
</paths>