数据意图返回 null

我有一个机器人应用程序,其中包含多个活动。

在其中一个里面,我使用了一个按钮,它会调用设备摄像头:

public void onClick(View view) {
Intent photoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(photoIntent, IMAGE_CAPTURE);
}

在同一个活动中,我为图像结果调用 OnActivityResult方法:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == IMAGE_CAPTURE) {
if (resultCode == RESULT_OK) {
Bitmap image = (Bitmap) data.getExtras().get("data");
ImageView imageview = (ImageView) findViewById(R.id.pic);
imageview.setImageBitmap(image);
} else if (resultCode == RESULT_CANCELED) {
Toast.makeText(this, "CANCELED ", Toast.LENGTH_LONG).show();
}
}
}

问题是意图 data为空,而 OnActivityResult方法直接转向 (resultCode == RESULT_CANCELED),应用程序返回到之前的活跃状态。

我如何修复这个问题,并在调用相机后,应用程序返回到当前的活动,其中包含一个 ImageView将包含的照片?

谢谢

134797 次浏览

以下代码适用于我:

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

结果是这样的:

protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent)
{
super.onActivityResult(requestCode, resultCode, imageReturnedIntent);


if(resultCode == RESULT_OK)
{
Uri selectedImage = imageReturnedIntent.getData();
ImageView photo = (ImageView) findViewById(R.id.add_contact_label_photo);
Bitmap mBitmap = null;
try
{
mBitmap = Media.getBitmap(this.getContentResolver(), selectedImage);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}

默认的 Android 摄像头应用程序只有在返回意图中的缩略图时才返回非空意图。如果将要写入的 URI 传递给 EXTRA_OUTPUT,它将返回一个 null意图,并且图片位于您传递的 URI 中。

你可以通过查看 GitHub 上的摄像头应用程序源代码来验证这一点:

I would guess that you're either passing in EXTRA_OUTPUT somehow, or the camera app on your phone works differently.

也许是因为你有这样的东西?

Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri fileUri =  CommonUtilities.getTBCameraOutputMediaFileUri();
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
startActivityForResult(takePictureIntent, 2);

但是,您不能将额外的输出放入意图中,因为那样数据就会进入 URI 而不是数据变量。因为这个原因,你必须去掉中间的两条线

Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(takePictureIntent, 2);

这就是我的问题所在,希望能有所帮助。

我找到了一个简单的答案。它的工作! !

private void openCameraForResult(int requestCode){
Intent photo = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri uri  = Uri.parse("file:///sdcard/photo.jpg");
photo.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(photo,requestCode);
}


if (requestCode == CAMERA_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
File file = new File(Environment.getExternalStorageDirectory().getPath(), "photo.jpg");
Uri uri = Uri.fromFile(file);
Bitmap bitmap;
try {
bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
bitmap = cropAndScale(bitmap, 300); // if you mind scaling
profileImageView.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


}
}

如果你想裁剪和缩放这个图像

public static  Bitmap cropAndScale (Bitmap source, int scale){
int factor = source.getHeight() <= source.getWidth() ? source.getHeight(): source.getWidth();
int longer = source.getHeight() >= source.getWidth() ? source.getHeight(): source.getWidth();
int x = source.getHeight() >= source.getWidth() ?0:(longer-factor)/2;
int y = source.getHeight() <= source.getWidth() ?0:(longer-factor)/2;
source = Bitmap.createBitmap(source, x, y, factor, factor);
source = Bitmap.createScaledBitmap(source, scale, scale, false);
return source;
}

访问照相机,拍照并在 Android 上设置 ImageView

你必须使用 Uri file = Uri.fromFile(getOutputMediaFile());棉花糖。

使用下面的链接获取路径

Https://androidkennel.org/android-camera-access-tutorial/

简单的工作摄像头应用程序避免空意图问题

- 所有修改的代码包括在这个答复中; 接近安卓教程

我已经花了很多时间在这个问题上,所以我决定创建一个帐户,并与您分享我的成果。

官方的安卓教程 “简单拍照”并没有实现它的承诺。 这里提供的代码在我的设备上无法工作: 一个三星Galaxy S4的 Mini gT-I9195运行 android 版本4.4.2/KitKat/API Level 19。

我发现主要问题是在捕获照片时调用的方法中的下面一行(教程中的 dispatchTakePictureIntent) :

takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);

它导致随后被 onActivityResult捕获的意图为空。

为了解决这个问题,我从这里的早期回复和一些关于 github 的有用帖子中找到了很多灵感(大部分是 这一次是在深冬——非常感谢他; 你可能也想看看他在一个紧密相关的 邮寄上的回复)。

遵循这些令人愉快的建议,我选择了删除上面提到的 putExtra行的策略,并在 onActivityResult ()方法中执行相应的操作,即从相机返回拍摄的照片。 返回与图片相关的位图的决定性代码行如下:

        Uri uri = intent.getData();
Bitmap bitmap = null;
try {
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
} catch (IOException e) {
e.printStackTrace();
}

我创建了一个示范应用程序,它只是有能力采取的图片,保存在 SD 卡和显示它。 我认为这可能会对我遇到这个问题时遇到的同样情况的人有所帮助,因为当前的帮助建议大多是指相当广泛的 gitub 帖子,这些帖子可以做相关的事情,但是对于像我这样的新手来说不太容易监督。 关于 Android Studio 在创建新项目时每次默认创建的文件系统,我只需要为我的目的修改三个文件:

Activity _ main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.android.simpleworkingcameraapp.MainActivity">


<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="takePicAndDisplayIt"
android:text="Take a pic and display it." />


<ImageView
android:id="@+id/image1"
android:layout_width="match_parent"
android:layout_height="200dp" />


</LinearLayout>

MainActivity.java:

package com.example.android.simpleworkingcameraapp;


import android.content.Intent;
import android.graphics.Bitmap;
import android.media.Image;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;


import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;


public class MainActivity extends AppCompatActivity {


private ImageView image;
static final int REQUEST_TAKE_PHOTO = 1;
String mCurrentPhotoPath;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
image = (ImageView) findViewById(R.id.image1);
}


// copied from the android development pages; just added a Toast to show the storage location
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmm").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName,  /* prefix */
".jpg",         /* suffix */
storageDir      /* directory */
);


// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = image.getAbsolutePath();
Toast.makeText(this, mCurrentPhotoPath, Toast.LENGTH_LONG).show();
return image;
}


public void takePicAndDisplayIt(View view) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (intent.resolveActivity(getPackageManager()) != null) {
File file = null;
try {
file = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
}


startActivityForResult(intent, REQUEST_TAKE_PHOTO);
}
}


@Override
protected void onActivityResult(int requestCode, int resultcode, Intent intent) {
if (requestCode == REQUEST_TAKE_PHOTO && resultcode == RESULT_OK) {
Uri uri = intent.getData();
Bitmap bitmap = null;
try {
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
} catch (IOException e) {
e.printStackTrace();
}
image.setImageBitmap(bitmap);
}
}
}

Xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.simpleworkingcameraapp">




<!--only added paragraph-->
<uses-feature
android:name="android.hardware.camera"
android:required="true" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  <!-- only crucial line to add; for me it still worked without the other lines in this paragraph -->
<uses-permission android:name="android.permission.CAMERA" />




<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />


<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>


</manifest>

注意,我找到的解决问题的方法也导致了 android 清单文件的简化: android 教程建议的关于添加提供程序的更改不再需要,因为我没有在我的 Java 代码中使用任何提供程序。因此,只有很少的标准行(主要是关于权限)必须添加到清单文件中。

指出 Android Studio 的自动导入可能不能处理 java.text.SimpleDateFormatjava.util.Date可能更有价值。我不得不手动导入它们。

我曾经经历过这个问题,intent不是空的,但是通过这个 intent发送的信息在 onActionActivit()中没有接收到

enter image description here

这是使用 GetContentResolver ()的一个更好的解决方案:

    private Uri imageUri;
private ImageView myImageView;
private Bitmap thumbnail;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);


...
...
...
myImageview = (ImageView) findViewById(R.id.pic);


values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, "MyPicture");
values.put(MediaStore.Images.Media.DESCRIPTION, "Photo taken on " + System.currentTimeMillis());
imageUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, PICTURE_RESULT);


}

onActivityResult()得到一个由 GetContentResolver ()存储的位图:

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


if (requestCode == REQUEST_CODE_TAKE_PHOTO && resultCode == RESULT_OK) {


Bitmap bitmap;
try {
bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), imageUri);
myImageView.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}


}
}

introducir la descripción de la imagen aquí introducir la descripción de la imagen aquí

看看我在 github 中的例子:

Https://github.com/jorgesys/takepicture

科特林密码对我很管用:

 private fun takePhotoFromCamera() {
val intent = Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE)
startActivityForResult(intent, PERMISSIONS_REQUEST_TAKE_PICTURE_CAMERA)
}

结果是:

 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == PERMISSIONS_REQUEST_TAKE_PICTURE_CAMERA) {
if (resultCode == Activity.RESULT_OK) {
val photo: Bitmap? =  MediaStore.Images.Media.getBitmap(this.contentResolver, Uri.parse( data!!.dataString)   )
// Do something here : set image to an ImageView or save it ..
imgV_pic.imageBitmap = photo
} else if (resultCode == Activity.RESULT_CANCELED) {
Log.i(TAG, "Camera  , RESULT_CANCELED ")
}


}


}

别忘了声明请求代码:

companion object {
const val PERMISSIONS_REQUEST_TAKE_PICTURE_CAMERA = 300
}

经过多次尝试和研究,我终于弄明白了。首先,来自 Inent 的变量数据将始终为 null,因此,检查 !null将使您的应用程序崩溃,只要您将 URI 传递给 startActivityForResult。按照下面的例子。 我会利用科特林。

  1. 打开摄像机

    fun addBathroomPhoto(){
    addbathroomphoto.setOnClickListener{
    
    
    request_capture_image=2
    
    
    var takePictureIntent:Intent?
    takePictureIntent =Intent(MediaStore.ACTION_IMAGE_CAPTURE)
    if(takePictureIntent.resolveActivity(activity?.getPackageManager()) != null){
    
    
    val photoFile: File? = try {
    createImageFile()
    } catch (ex: IOException) {
    // Error occurred while creating the File
    
    
    null
    }
    
    
    if (photoFile != null) {
    val photoURI: Uri = FileProvider.getUriForFile(
    activity!!,
    "ogavenue.ng.hotelroomkeeping.fileprovider",photoFile)
    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
    photoURI);
    startActivityForResult(takePictureIntent,
    request_capture_image);
    }
    
    
    
    
    }
    
    
    }
    

    }`

  2. 创建 createImageFile ()。但是您必须使 imageFilePath 变量为全局变量。关于如何创建它的示例在 Android 官方文档中有,而且非常简单

  3. 获取意图

     override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    
    
    if (requestCode == 1 && resultCode == RESULT_OK) {
    add_room_photo_txt.text=""
    var myBitmap=BitmapFactory.decodeFile(imageFilePath)
    addroomphoto.setImageBitmap(myBitmap)
    var file=File(imageFilePath)
    var fis=FileInputStream(file)
    var bm = BitmapFactory.decodeStream(fis);
    roomphoto=getBytesFromBitmap(bm) }}
    
  4. The getBytesFromBitmap method

      fun getBytesFromBitmap(bitmap:Bitmap):ByteArray{
    
    
    var stream=ByteArrayOutputStream()
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
    return stream.toByteArray();
    }
    

I hope this helps.

我使用 contentResolver 来创建路径,它起作用了。

var values = ContentValues()
values.put(MediaStore.Images.Media.TITLE, "MyPicture")
values.put(
MediaStore.Images.Media.DESCRIPTION,
"Photo taken on " + System.currentTimeMillis()
)
cameraUri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)


val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
cameraIntent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, cameraUri);
startActivityForResult(cameraIntent, REQUEST_CODE)


即使到了2022年,这种情况依然存在,我把它修正如下:

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // android7.0
photoUri= FileProvider.getUriForFile(
MainActivity.this,
BuildConfig.APPLICATION_ID + ".provider",
new File(mCameraFilePath));
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
} else {
photoUri = Uri.fromFile(new File(mCameraFilePath));
intent.putExtra(MediaStore.EXTRA_OUTPUT,photoUri);
}

哦... 只要添加一个活跃的(photoUri)到您的活动! 然后

filePathCallback.onReceiveValue(new Uri[]{ photoUri });