Search code examples
androidfirebasefile-uploadcamerafirebase-storage

Upload image error: Attempt to invoke virtual method 'java.lang.String android.net.Uri.getLastPathSegment()' on a null object reference


I have a problem with "capture image with camera", and store it into Firebase. I think that the code is right, because it worked with "select image from gallery". The app stoped after capturing the image, and it didn't store it into the database. I think that it is a problem for android M and N (Android 6 and 7). There is also the error in logcat.

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


    if (requestCode == CAMERA_REQUEST_CODE && resultCode == RESULT_OK){
        mPregresDialog.setMessage("Uploading...");
        mPregresDialog.show();

        Uri uri = data.getData();
        StorageReference filepath = mStorage.child("Photo").child(uri.getLastPathSegment());
        filepath.putFile(uri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
            @Override
            public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
                mPregresDialog.dismiss();

                Toast.makeText(MainActivity.this, "Upload Done", Toast.LENGTH_LONG).show();

            }
        });

    }}

logcat:

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.net.Uri.getLastPathSegment()' on a null object reference


Solution

  • The problem is that your Uri does not get the image as it should so you need to create your own Uri for your image you capture.

    You need to go to android documentation: https://developer.android.com/training/camera/photobasics.html#TaskPhotoView

    For your app, you can also just copy and paste this code in your main activity:

    String mCurrentPhotoPath;
    
    private File createImageFile() throws IOException {
    // Create an image file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").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();
    return image;
    }
    
    private void dispatchTakePictureIntent() {
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    // Ensure that there's a camera activity to handle the intent
    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
        // Create the File where the photo should go
        File photoFile = null;
        try {
            photoFile = createImageFile();
        } catch (IOException ex) {
            // Error occurred while creating the File...
        }
        // Continue only if the File was successfully created
        if (photoFile != null) {
            Uri photoURI = FileProvider.getUriForFile(this,
                    "com.example.android.fileprovider",
                    photoFile);
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
            startActivityForResult(takePictureIntent, CAMERA_REQUEST_CODE);
        }
    }
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    storage = FirebaseStorage.getInstance().getReference();
    
    b_gallery = (Button) findViewById(R.id.b_gallery);
    b_capture = (Button) findViewById(R.id.b_capture);
    iv_image = (ImageView) findViewById(R.id.iv_image);
    
    progressDialog = new ProgressDialog(this);
    
    b_capture.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            //Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            dispatchTakePictureIntent();
    
        }
    });
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    
    if(requestCode == CAMERA_REQUEST_CODE && resultCode == RESULT_OK){
        progressDialog.setMessage("Uploading...");
        progressDialog.show();
        Uri uri = data.getData();
    
        StorageReference filepath =     storage.child("Photos").child(uri.getLastPathSegment());
        filepath.putFile(photoURI).addOnSuccessListener(new    OnSuccessListener<UploadTask.TaskSnapshot>() {
            @Override
            public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
                Toast.makeText(MainActivity.this, "Upload Successful!",    Toast.LENGTH_SHORT).show();
                progressDialog.dismiss();
            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                Toast.makeText(MainActivity.this, "Upload Failed!", Toast.LENGTH_SHORT).show();
            }
        });
        }
    }
    }
    

    And make sure you follow the documentation and have added the provider in your AndroidManifest.xml:

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

    And the res/xml/file_paths.xml (you just make a directory under "res" folder and name it xml, then you create a resource file and name it file_paths.xml); then delete all the code inside it (it'll have some lines) and paste the following:

    <?xml version="1.0" encoding="utf-8"?>
    <paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images"       path="Android/data/com.serjardovic.firebasesandbox/files/Pictures" />
    </paths>
    

    Make sure you CHANGE the com.serjardovic.firebasesandbox to your own package name!