在 ACTION_GET_CONTENT 意图之后有时不会调用 OnActivityResult

Posted

技术标签:

【中文标题】在 ACTION_GET_CONTENT 意图之后有时不会调用 OnActivityResult【英文标题】:OnActivityResult sometimes not called after ACTION_GET_CONTENT intent 【发布时间】:2018-05-18 22:01:17 【问题描述】:

我正在开发一个图像编辑 android 应用程序。在我的一项活动中,我调用了从 onCreate() 中的图库中选择图像的意图,如下所示:

Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select Picture"), PICK_IMAGE);

然后我收到这样的数据:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) 
    Crashlytics.log("onActivityResult called");
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == PICK_IMAGE && resultCode == Activity.RESULT_OK && data != null) 
        Crashlytics.log("Data received from image pick intent");
        imageUri = data.getData();
        loadImage();
     else 
        //if we do not select a picture, go back to the dashboard
        Crashlytics.log("Data not received");
        onBackPressed();
        Log.d(TAG, "no picture selected");
    

loadImage 方法:

private void loadImage() 
    try 
        photoBitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
     catch (IOException e) 
        Crashlytics.log("IOException from getBitmap");
        Log.d(TAG, e.getMessage());
        showToastAndPressBack();
        return;
    

    if (photoBitmap == null) 
        Crashlytics.log("photoBitmap is null in onActivityResult");
        showToastAndPressBack();
        return;
    

    Display display = getWindowManager().getDefaultDisplay();
    Point size = new Point();
    display.getSize(size);
    imgVWidth = size.x;
    int height = size.y;
    imgVHeight = (int) (((float) imgVWidth / photoBitmap.getWidth()) * photoBitmap.getHeight());
    photoInImgViewBitmap = Bitmap.createScaledBitmap(photoBitmap, imgVWidth, imgVHeight, true);
    imageAlreadyPicked = true;

现在我的问题是,有时我在 Crashlytics 中看到 NPE-s 声称当用户按下下一个按钮时 photoBitmap 为空。

@OnClick(R.id.toolbar_next)
void onToolbarNextClick() 
    float originalScale = (float) (previewImageView.getHeight()) / (float) (photoBitmap.getHeight());
    ...

我看到的唯一 Crashlytics 日志是用户离开的意图(我在 onPause 中放置了一个 Crashlytics 日志)。 onActivityResult 没有日志,所以我最好的猜测是 onActivityResult 没有被调用,因此我的位图没有加载,因此当用户按下下一步时它将为空。

问题:为什么有时会调用onActivityResult,有时不调用? photoBitmap 为空还有其他可能的原因吗?

【问题讨论】:

当用户从这个屏幕导航到下一个屏幕时会发生异常。如果是由于位图加载,我们会在 onActivityResult 中检测到,正如您在代码示例中看到的那样。 是的,我正在覆盖它- 如果是由于 onBackPressed 不起作用,我会看到调用 onActivityResult 的 crashlytics 日志 photoBitmap.getHeight());。如果photoBitmap==null,请勿使用此代码。就这样!使用前检查是否为空。 真的是这样吗?这听起来像是在不知道根本原因的情况下快速解决问题。一定有它为空的原因。我可以通过没有调用 onActivityResult 的 crashyltics 日志检测到它。这是为什么呢? 【参考方案1】:

您必须添加以下代码才能从设备中获取图像

choosebtn.setOnClickListener(new View.OnClickListener() 
     @Override
     public void onClick(View v) 
         Intent i1=new Intent();
         i1.setType("image/*");
         i1.setAction(Intent.ACTION_GET_CONTENT);
         startActivityForResult(i1,1);
      
);


@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) 
    super.onActivityResult(requestCode, resultCode, data);
    if(requestCode == 1 && resultCode == RESULT_OK && data != null && data.getData() != null)
    
        imguri=data.getData();
        mainpreview.setImageURI(data.getData());
     else 
        Toast.makeText(getApplicationContext(),"please choose image",Toast.LENGTH_SHORT).show();
    

【讨论】:

很奇怪的问题线程,这应该是一个可以接受的答案,但它甚至没有一票【参考方案2】:

试试这个,效果很好

     Intent i = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
            startActivityForResult(i, LOAD_IMAGE_RESULTS);

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

           if (requestCode == LOAD_IMAGE_RESULTS && resultCode == RESULT_OK && data != null) 
                    // Let's read picked image data - its URI
                    Uri pickedImage = data.getData();

                    // Let's read picked image path using content resolver
                    String[] filePath = MediaStore.Images.Media.DATA;
                    @SuppressLint("Recycle") Cursor cursor = null;
                    if (pickedImage != null) 
                        cursor = getContentResolver().query(pickedImage, filePath, null, null, null);
                    
                    if (cursor != null) 
                        cursor.moveToFirst();

                        String imagePath = cursor.getString(cursor.getColumnIndex(filePath[0]));
      
    

现在您可以将imagepath 转换为位图

【讨论】:

@SupressLint("Recycle") 的目的是什么?【参考方案3】:

在您的代码最后一行方法之后调用super.onActivityResult。当你调用 super 时,你已经告诉 android 你已经完成了。

我还注意到您记录了一个字符序列。不要那样做你不会用这个来解决任何问题。

 Crashlytics.log("Data not received");

您需要保存一些数据。考虑到用户取消了,因为您的代码没有捕捉到这一点。

/* 假设 log 方法有一个 int 输入 */

Crashlytics.log("Data not received");
Crashlytics.log(requestCode);
Crashlytics.log(resultCode);

【讨论】:

我不想用那个日志来修复任何东西。只是想找出执行哪些代码路径。如果您阅读问题,您会看到我写道:“我看到的唯一 Crashlytics 日志是用户离开的意图(我在 onPause 中放置了 Crashlytics 日志)。没有 onActivityResult 的日志”你看到了吗?没有一条日志暗示 onActivityResult 已被调用。 是的,我确实阅读了这个问题。当您开始意图时,您没有显示您已登录。我怎么能相信一个字符序列就足以知道意图已经完成了。 我在 onPause 中输入了一个日志。找不到任何其他方法来知道是否调用了意图。所以织物只报告了一个日志:“用户左屏”(我在暂停时打印出来)。之后,用户使用空照片位图按下下一步,应用程序崩溃。没有 onActivityResult 日志。 为什么会出现空值。用户刷掉了照片选择器。用户被通知或短信分散了注意力,并将您的应用程序留在了后台。或者两个多月后我最喜欢的用户切换回你的应用程序,我在这里。看看你是否对此有进一步的了解。您是否弄清楚了 NPE 您可以使用 kotlin 来掩盖 NPE。考虑将对 super 的调用移至方法中的最后一行代码。【参考方案4】:

使用它从图库中选择:

Intent i = new Intent(Intent.ACTION_PICK);
i.setType("image/*");
startActivityForResult(i, REQUEST_CODE);

现在你会在 onActivityResult 中得到一个回调:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) 
    switch (requestCode) 
        case REQUEST_CODE:
            if (resultCode != RESULT_CANCELED) 
//use data to get the selected image
            
            break;
    

【讨论】:

【参考方案5】:

要启动相机活动,请使用此代码

Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, CAMERA_REQUEST);

获取位图

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

  if(resultCode == Activity.RESULT_OK)
    if(requestCode==CAMERA_REQUEST) 
      Bitmap photo = (Bitmap) data.getExtras().get("data"); 
    else
      //Camera request cancelled
  

【讨论】:

以上是关于在 ACTION_GET_CONTENT 意图之后有时不会调用 OnActivityResult的主要内容,如果未能解决你的问题,请参考以下文章

获取图像的 ACTION_GET_CONTENT 返回空 URI

意图:删除始终/仅一次按钮

Android:如何在 ACTION_GET_CONTENT 中设置初始目录

从隐式意图返回 FilePath

从意图中获取所选文件的文件扩展名

将意图文件路径共享给文件管理器以打开该路径