Camera “Bitmap imageBitmap = (Bitmap) extras.get(”

2020-04-18 08:48发布

问题:

I am following the Android developer tutorials on camera here: https://developer.android.com/training/camera/photobasics#java

I however get an error in the method

onActivityResult:,java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.os.Bundle.get(java.lang.String)' on a null object reference

This line is giving the error:

Bitmap imageBitmap = (Bitmap) extras.get("data");

Somehow when I comment out this line then the app works:

takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);

My entire code is located here: https://github.com/europa9/EanScannerForAndroid

MainActivity.java

package one.askit.eanscanner;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.icu.text.SimpleDateFormat;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

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

public class MainActivity extends AppCompatActivity {
    static final int REQUEST_IMAGE_CAPTURE = 1;
    static final int REQUEST_TAKE_PHOTO = 1;


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

        // Permission
        checkPermissionExternalRead();
        checkPermissionExternalWrite();
        checkPermissionCamera();

        // Listeners
        listeners();

        FrameLayout frameLayoutCameraPreview = findViewById(R.id.frameLayoutCameraPreview);
        frameLayoutCameraPreview.setVisibility(View.GONE);

    }

    /*- Check permission Read ------------------------------------------------------------------- */
    // Pops up message to user for reading
    private void checkPermissionExternalRead(){
        int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 1;
        if (checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {

            // Should we show an explanation?
            if (shouldShowRequestPermissionRationale(
                    android.Manifest.permission.READ_EXTERNAL_STORAGE)) {
                // Explain to the user why we need to read the contacts
            }

            requestPermissions(new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE},
                    MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);

            // MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE is an
            // app-defined int constant that should be quite unique

            return;
        }
    } // checkPermissionRead

    /*- Check permission Write ------------------------------------------------------------------ */
    // Pops up message to user for writing
    private void checkPermissionExternalWrite(){
        int MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 1;
        if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {

            // Should we show an explanation?
            if (shouldShowRequestPermissionRationale(
                    android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                // Explain to the user why we need to read the contacts
            }

            requestPermissions(new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE);

            // MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE is an
            // app-defined int constant that should be quite unique

            return;
        }
    } // checkPermissionWrite

    /*- Check permission Camera ----------------------------------------------------------------- */
    public void checkPermissionCamera(){
        int MY_PERMISSIONS_REQUEST_CAMERA = 1;
        if (checkSelfPermission(Manifest.permission.CAMERA)
                != PackageManager.PERMISSION_GRANTED) {

            // Should we show an explanation?
            if (shouldShowRequestPermissionRationale(
                    Manifest.permission.CAMERA)) {
                // Explain to the user why we need to read the contacts
            }

            requestPermissions(new String[]{android.Manifest.permission.CAMERA},
                    MY_PERMISSIONS_REQUEST_CAMERA);

            // MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE is an
            // app-defined int constant that should be quite unique

            return;
        }
    } // checkPermissionInternalRead


    public void listeners(){
        Button buttonScan = findViewById(R.id.buttonScan);
        buttonScan.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                buttonScanClicked();
            }
        });

    }
    public void buttonScanClicked(){
        // Scan text
        TextView TextViewScan = findViewById(R.id.TextViewScan);
        TextViewScan.setText("Now scanning");

        // Take picture
        dispatchTakePictureIntent();
    }

    private void dispatchTakePictureIntent() {
        Intent picIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE).addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

        String file_path = Environment.getExternalStorageDirectory().toString() +
                "/" + this.getResources().getString(R.string.app_name);

        File dir = new File(file_path);
        if (!dir.exists())
            dir.mkdirs();
        // IMAGE_PATH = new File(dir, mContext.getResources().getString(R.string.app_name) + AppConstants.USER_ID + System.currentTimeMillis() + ".png");

        File IMAGE_PATH = new File(dir, this.getResources().getString(R.string.app_name) + System.currentTimeMillis() + ".png");

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            picIntent.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(this, this.getPackageName() + ".fileprovider", IMAGE_PATH));
        }
        else {
            picIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(IMAGE_PATH));
        }

        startActivityForResult(picIntent, REQUEST_TAKE_PHOTO);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
            Bundle extras = data.getExtras();
            if (extras != null) {
                //Do your logic
                Bitmap imageBitmap = (Bitmap) extras.get("data");
                ImageView imageViewScanPreview = findViewById(R.id.imageViewScanPreview);
                imageViewScanPreview.setImageBitmap(imageBitmap);
            } else {
                //Do something else
                Toast.makeText(this, "Its null!", Toast.LENGTH_LONG).show();
            }

        }
    }

}

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"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:id="@+id/frameLayoutCameraPreview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1" />

    <ImageView
        android:id="@+id/imageViewScanPreview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:srcCompat="?attr/colorAccent" />

    <TextView
        android:id="@+id/TextViewScan"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Doint nothing"></TextView>

    <Button
        android:id="@+id/buttonScan"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Scan" />
</LinearLayout>

AndroidManifest.xml

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

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



    <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>

        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

    </application>

</manifest>

file_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="images" path="."/>
    <external-path name="external_files" path="."/>
</paths>

回答1:

Change your file provider like below

    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="${applicationId}.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
    </provider>

And your file_path.xml be like below

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="images" path="."/>

    <external-path name="external_files" path="."/>

</paths>

For image capture use this Intent

  Intent picIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE).addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);


        String file_path = Environment.getExternalStorageDirectory().toString() +
                "/" + mContext.getResources().getString(R.string.app_name);

        File dir = new File(file_path);
        if (!dir.exists())
            dir.mkdirs();
       // IMAGE_PATH = new File(dir, mContext.getResources().getString(R.string.app_name) + AppConstants.USER_ID + System.currentTimeMillis() + ".png");

        IMAGE_PATH = new File(dir, mContext.getResources().getString(R.string.app_name) + System.currentTimeMillis() + ".png");

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            picIntent.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(mContext, mContext.getPackageName()+".fileprovider", IMAGE_PATH));
        }
        else {
            picIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(IMAGE_PATH));
        }

        ((Activity) mContext).startActivityForResult(picIntent, CAMERA_REQUEST);

And inside the onActivityREsult , you need to change the code as follow

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

        int cropperType = 1;
        if (requestCode == REQUEST_IMAGE_CAPTURE) {

            switch (resultCode) {
                case Activity.RESULT_OK:

                     String imagePAth= Uri.fromFile(IMAGE_PATH);
                GlideApp.with(this).load(imagePAth).diskCacheStrategy(DiskCacheStrategy.ALL).skipMemoryCache(false).
                        placeholder(R.drawable.default_picture).error(R.drawable.default_picture).dontAnimate().into(YOUR_IMAGEVIEW);

                    break;
                case Activity.RESULT_CANCELED:

                    break;
            }
        }

    } 

And if you want the Bitmap from the onActivityResult than you need to refer this link Click here



回答2:

There are different ways to receive a bitmap from the camera.

You are trying to get a Bitmap from the extras that is not there. Since you are casting the null to Bitmap the error happens at the moment of accessing the data and not the moment you try to work with the bitmap.

If your are supplying a output URI via takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); most Android phones will store the photo at this URI and you have to access the bitmap through the file that was stored there. If you remove the URI the photo is supplied in the extra in the Intent, that is why the code works if you remove that line.