android 中手机的相机应用拍照后 onActivityResult 出现空指针异常

Null Pointer Exception in onActivityResult after taking photo in Camera app of the mobile in android

这是我的 UnityBridge 的代码,我用它来桥接 Unity 和 Native Android。

Unity 和 android 之间的桥接成功。当我从 Unity 调用 openCamera 方法时,相机应用程序打开,我可以拍照。拍照后图像保存到内存中的 Demo 文件夹中。直到这一步没有问题,但是保存照片后应用程序强制关闭。我从 cmd 得到了这样的日志:我认为在 onActivityResult 中获得的 Intent 数据是空的。有人可以帮我解决这个错误吗?我需要将图像保存到存储卡中的 Demo 文件夹中,并将包括所拍摄照片的文件名在内的完整文件路径获取到一个字符串变量中,以便我可以将该完整文件路径返回统一以进行下一步处理。可能吗?

Logcat

E/AndroidRuntime( 1873): Caused by: java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=100, result=-1, data=null} to activity {com.tony.example/com.tony.example.UnityBridge}: java.lang.NullPointerException E/AndroidRuntime( 1873): at android.app.ActivityThread.deliverResults(ActivityThread.java:3205) E/AndroidRuntime( 1873): at android.app.ActivityThread.handleSendResult(ActivityThread.java:3248) E/AndroidRuntime( 1873): at android.app.ActivityThread.access00(ActivityThread.java:140) E/AndroidRuntime( 1873): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1285) E/AndroidRuntime( 1873): at android.os.Handler.dispatchMessage(Handler.java:99) E/AndroidRuntime( 1873): at android.os.Looper.loop(Looper.java:137) E/AndroidRuntime( 1873): at android.app.ActivityThread.main(ActivityThread.java:4921) E/AndroidRuntime( 1873): at java.lang.reflect.Method.invokeNative(NativeMethod) E/AndroidRuntime( 1873): at java.lang.reflect.Method.invoke(Method.java:511) E/AndroidRuntime( 1873): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1027) E/AndroidRuntime( 1873): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794) E/AndroidRuntime( 1873): at dalvik.system.NativeStart.main(Native Method) E/AndroidRuntime( 1873): Caused by: java.lang.NullPointerException E/AndroidRuntime( 1873): at com.tony.example.UnityBridge.onActivityResult(UnityBridge.java:154) E/AndroidRuntime( 1873): at android.app.Activity.dispatchActivityResult(Activity.java:5390) E/AndroidRuntime( 1873): at android.app.ActivityThread.deliverResults(ActivityThread.java:3201) E/AndroidRuntime( 1873): ... 11 more

代码

package com.tony.example;

import java.io.ByteArrayOutputStream;
import java.io.File;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.widget.Toast;

import com.unity3d.player.UnityPlayerActivity;
import com.unity3d.player.UnityPlayer;

public class UnityBridge extends UnityPlayerActivity
{    
static private int _myInt;
private static int RESULT_LOAD_IMAGE = 1;
private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100;
public static final int MEDIA_TYPE_IMAGE = 1;
private Uri fileUri;
private Context context;
private static UnityBridge instance;
public Bitmap imgbitmap;
public String picturepath;

public UnityBridge() {
    this.instance = this;
}

public static UnityBridge instance() {
    if(instance == null) {
        instance = new UnityBridge();
    }
    return instance;
}

public void setContext(Context context) {
    this.context = context;
}

public void openCamera()
{
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // create a file to save the image
    intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name

    // start the image capture Intent
    startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
}
/** Create a file Uri for saving an image or video */
private static Uri getOutputMediaFileUri(int type){
      return Uri.fromFile(getOutputMediaFile(type));
}

/** Create a File for saving an image or video */
private static File getOutputMediaFile(int type){
    // To be safe, you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this.

    File mediaStorageDir = new File(android.os.Environment.getExternalStorageDirectory(), "Demo");
    // This location works best if you want the created images to be shared
    // between applications and persist after your app has been uninstalled.

    // Create the storage directory if it does not exist
    if (! mediaStorageDir.exists()){
        if (! mediaStorageDir.mkdirs()){
            Log.d("Demo", "failed to create directory");
            return null;
        }
    }

    // Create a media file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    File mediaFile;
    if (type == MEDIA_TYPE_IMAGE){
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
        "IMG_"+ timeStamp + ".jpg");
    } else {
        return null;
    }

    return mediaFile;
}


@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    Log.d("Request Code: "+requestCode,"Result Code: "+resultCode);

    if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
        if (resultCode == RESULT_OK) {
            // Image captured and saved to fileUri specified in the Intent
            Toast.makeText(this.context, "Image saved to:\n" +
                     data.getData(), Toast.LENGTH_LONG).show();
        } else if (resultCode == RESULT_CANCELED) {
            Toast.makeText(this.context, "Image Capture cancelled by the user", Toast.LENGTH_LONG).show();
            // User cancelled the image capture
        } else {
            // Image capture failed, advise user
            Toast.makeText(this.context,"Something unexpected happened, Please check your Camera",Toast.LENGTH_LONG).show();
        }
    }

}

public void showMessage(String message) {
    Toast.makeText(this.context, message, Toast.LENGTH_SHORT).show();
}
}

NPE 在这里: Toast.makeText(this.context, "Image saved to:\n" + data.getData(), Toast.LENGTH_LONG).show();

因为当您启动 activity(相机)时,将保存包含照片的文件,并且 Intent data 参数将为空。

如果未设置 EXTRA_OUTPUT,则 Intent 参数中会返回

data。 它将包含照片本身,而不是它的路径。

为了避免 NPE 使用这个 toast(没有数据参数) Toast.makeText(this.context, "Image saved", Toast.LENGTH_LONG).show();

编辑:

使用这个获取存储目录,这样它会被保存到images文件夹 gallery

可以发现
File storageDir = Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES);

要显示保存路径,请在创建文件时使用全局 String 变量存储文件路径,然后在 toast 中显示它。

opencamera()方法中:

fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
globalStringFilePath = fileUri .getAbsolutePath();

那么你的祝酒词就是

Toast.makeText(this.context, "Image saved to:\n" + globalStringFilePath , Toast.LENGTH_LONG).show()