相机结果代码和 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>