【问题标题】:Null URI on API level >=23 camera intent [duplicate]API 级别的空 URI >=23 相机意图 [重复]
【发布时间】:2018-06-07 08:05:00
【问题描述】:

这可能是重复的,但我似乎无法确定确切的解决方案。 相机工作正常,并在 api 23 以下的设备上返回图像 uri。 但是,在 apove api 23 设备上捕获图像后,应用程序立即崩溃并出现日志错误

java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=2, result=-1, data=Intent { act=inline-data (has extras) }} to activity {ana.foodi/ana.foodi.MainActivity}: java.lang.NullPointerException: uri
                                                         at android.app.ActivityThread.deliverResults(ActivityThread.java:3940)
                                                         at android.app.ActivityThread.handleSendResult(ActivityThread.java:3983)
                                                         at android.app.ActivityThread.-wrap16(ActivityThread.java)
                                                         at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1548)
                                                         at android.os.Handler.dispatchMessage(Handler.java:111)
                                                         at android.os.Looper.loop(Looper.java:207)
                                                         at android.app.ActivityThread.main(ActivityThread.java:5765)
                                                         at java.lang.reflect.Method.invoke(Native Method)
                                                         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
                                                         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679)
                                                      Caused by: java.lang.NullPointerException: uri
                                                         at com.android.internal.util.Preconditions.checkNotNull(Preconditions.java:60)
                                                         at android.content.ContentResolver.query(ContentResolver.java:481)
                                                         at android.content.ContentResolver.query(ContentResolver.java:441)
                                                         at ana.foodi.MainActivity.onActivityResult(MainActivity.java:672)

用断点检查后,实现 Uri (selectedImage) 下面为空:

 @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    final String filePath;
    if(resultCode == Activity.RESULT_OK && REQUEST_POST_PHOTO==999){


        if(requestCode == 2 ) {
            requestRuntimePermission();
            Uri selectedImage = data.getData();
            String[] filePaths = {MediaStore.Images.Media.DATA};
            Cursor c = this.getContentResolver().query(selectedImage, filePaths, null, null, null);
            c.moveToFirst();
            int columnIndex = c.getColumnIndex(filePaths[0]);
            filePath = c.getString(columnIndex);
            c.close();

我试过用这个请求运行时权限

public void requestRuntimePermission() {
    if (Build.VERSION.SDK_INT >= 23) {
        if (ContextCompat.checkSelfPermission(context,android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this,
                    new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
        }
    }
}

但错误仍然存​​在。

startActivityForResult 调用

REQUEST_POST_PHOTO=999;
                Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
                startActivityForResult(cameraIntent, REQUEST_CODE_POST);

【问题讨论】:

  • 您只需要 WRITE_EXTERNAL_STORAGE 权限。您需要所有 dangerous 级别的权限。在this link 上,每个权限都有一个保护级别 字段。
  • “相机工作正常,并在 api 23 以下的设备上返回图像 uri”——您没有显示您的 startActivityForResult() 调用。如果您使用的是ACTION_IMAGE_CAPTURE,它不应该返回Uri,并且很少有设备会有一个返回Uri的相机应用程序。
  • @CommonsWare 添加

标签: android nullpointerexception android-6.0-marshmallow android-camera-intent android-api-levels


【解决方案1】:

您正在使用ACTION_IMAGE_CAPTUREACTION_IMAGE_CAPTURE 不应该通过onActivityResult() 返回Uri。相反,要么:

  • 您在ACTION_IMAGE_CAPTUREIntent 上提供EXTRA_OUTPUT,在这种情况下,图像应该保存到该位置(参见this sample app),或者

  • 您没有在ACTION_IMAGE_CAPTUREIntent 上提供EXTRA_OUTPUT,在这种情况下,您会通过"data" 额外获得一个缩略图Bitmap,在Intent 上额外发送到onActivityResult()

the documentation 对此进行了介绍。

一些有问题的相机应用返回Uri。不要指望这种行为,因为编写良好的相机应用不会。

【讨论】:

    【解决方案2】:
    private static final int REQUEST_CODE_IMAGE = 1000;
    private String importFileName = "";
    
    private void cameraIntent() {
        importFileName = getString(R.string.app_name) + new Random().nextInt();
        startActivityForResult(getCameraIntent(context, importFileName), REQUEST_CODE_IMAGE);
    }
    
    public Intent getCameraIntent(Context context, String fileName) {
        Intent chooserIntent = null;
        List<Intent> intentList = new ArrayList<>();
        Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        takePhotoIntent.putExtra("return-data", true);
        takePhotoIntent.putExtra(MediaStore.EXTRA_SCREEN_ORIENTATION, context.getResources().getConfiguration().orientation);
        takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(context.getExternalCacheDir(), fileName)));
        intentList = addIntentsToList(context, intentList, Collections.singletonList(takePhotoIntent));
    
        if (intentList.size() > 0) {
            String title = context.getResources().getString(R.string.choose);
            chooserIntent = Intent.createChooser(intentList.remove(intentList.size() - 1), title);
            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentList.toArray(new Parcelable[]{}));
        }
        return chooserIntent;
    }
    
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case REQUEST_CODE_IMAGE:
                if (resultCode == RESULT_OK) {
                    onCaptureImageResult(data);
                }
                break;
        }
    }
    
    private void onCaptureImageResult(Intent data) {
        Uri imageUri;
        if (data == null) {
            imageUri = Uri.fromFile(new File(getExternalCacheDir(), importFileName));
        } else {
            imageUri = data.getData();
            if (imageUri == null)
                imageUri = Uri.fromFile(new File(getExternalCacheDir(), importFileName));
        }
    }
    

    如果您从用户那里获得权限(相机、读/写外部存储权限),则此代码 sn-p 将正常工作。你可以调用cameraIntent()。

    【讨论】:

      【解决方案3】:

      试试这个

      同时使用WRITE_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE读写文件

      <uses-feature android:name="android.hardware.camera2" />
      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
      <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
      

      这里要求写权限&读权限添加多个权限

      public void requestRuntimePermission() {
          if (Build.VERSION.SDK_INT >= 23) {
              if (ContextCompat.checkSelfPermission(context,android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                      != PackageManager.PERMISSION_GRANTED) {
                  ActivityCompat.requestPermissions(this,
                          new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
              }
          }
      }
      

      查看Android 6.0 multiple permissions

      //检查权限是否授予,如果授予则调用此块

              Uri selectedImage = data.getData();
              String[] filePaths = {MediaStore.Images.Media.DATA};
              Cursor c = this.getContentResolver().query(selectedImage, filePaths, null, null, null);
              c.moveToFirst();
              int columnIndex = c.getColumnIndex(filePaths[0]);
              filePath = c.getString(columnIndex);
              c.close();
      

      【讨论】:

        【解决方案4】:

        至少对于旧版本,如果允许多选 (Intent#EXTRA_ALLOW_MULTIPLE),URI 将作为剪贴板数据返回:

        data.getClipData()
        

        请参阅 Intent#getClipData()ClipData

        检查那里是否正在返回数据:

        ClipData clipData = data.getClipData();
        Uri selectedImage = null;
        if (clipData != null) {
            selectedImage = clipData.getItemAt(0).getUri();
        } else {
            selectedImage = data.getData();
        }
        

        【讨论】:

        • 感谢您的建议。 clipdata 也是 null
        【解决方案5】:
         targetSdkVersion 21
         change your targetsdk version in build.gradle to marshmallow it will be solved. 
        

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-03-06
        • 1970-01-01
        • 2018-02-24
        • 2020-08-08
        • 1970-01-01
        • 1970-01-01
        • 2016-01-03
        • 1970-01-01
        相关资源
        最近更新 更多