简体   繁体   中英

How to save image(From Camera app) Uri in FileProvider?

I'm trying to take picture when Image clicked, and then save Image Uri in FileProvide.

In my app, when I take picture and save it. I can't save my pic in my database.

I got null point error Error message

Process: com.example.android.inventoryapp, PID: 7732
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1, data=Intent { act=inline-data (has extras) }} to activity {com.example.android.inventoryapp/com.example.android.inventoryapp.EditorActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.net.Uri.toString()' on a null object reference
    at android.app.ActivityThread.deliverResults(ActivityThread.java:4360)
    at android.app.ActivityThread.handleSendResult(ActivityThread.java:4402)
    at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:49)
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:193)
    at android.app.ActivityThread.main(ActivityThread.java:6669)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
 Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.net.Uri.toString()' on a null object reference
    at com.example.android.inventoryapp.EditorActivity.onActivityResult(EditorActivity.java:483)
    at android.app.Activity.dispatchActivityResult(Activity.java:7454)
    at android.app.ActivityThread.deliverResults(ActivityThread.java:4353)
    at android.app.ActivityThread.handleSendResult(ActivityThread.java:4402) 
    at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:49) 
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) 
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loop(Looper.java:193) 
    at android.app.ActivityThread.main(ActivityThread.java:6669) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) 

How to solve this problem? Here is my code,

My EditorActivity

TakePicture method

  private void takePicture() {
    Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    try {
        File photoFile = createImageFile();

        Log.d(LOG_TAG, "File: " + photoFile.getAbsolutePath());

        if (cameraIntent.resolveActivity(getPackageManager()) != null) {
            startActivityForResult(cameraIntent, REQUEST_IMAGE_CAPTURE);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }

CreateImageFile method

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

saveItem method

 ContentValues values = new ContentValues();
    if (mHasImage) {
        values.put(ItemContract.ItemEntry.COLUMN_PICTURE, mImgUri.toString());
    } else {
        Toast.makeText(this, "Take photo", Toast.LENGTH_SHORT).show();
        return;
    }

onActivity method

 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
        Log.i(LOG_TAG, "Uri: " + mImgUri.toString());
        mImgTxt.setText(mImgUri.toString());
        mImgBitmap = getBitmapFromUri(mImgUri);
        mImageClick.setImageBitmap(mImgBitmap);
    }
}

getBitmapFromUri method

private Bitmap getBitmapFromUri(Uri uri) {
    ParcelFileDescriptor parcelFileDescriptor = null;
    try {
        parcelFileDescriptor =
                getContentResolver().openFileDescriptor(uri, "r");
        FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
        Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
        parcelFileDescriptor.close();
        return image;
    } catch (Exception e) {
        Log.e(LOG_TAG, "Failed to load image.", e);
        return null;
    } finally {
        try {
            if (parcelFileDescriptor != null) {
                parcelFileDescriptor.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
            Log.e(LOG_TAG, "Error closing ParcelFile Descriptor");
        }
    }
}

Create a folder xml in res then create a file "my_paths" in this folder and paste below code

<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
    name="my_images"
    path="Android/data/YOUR_APP_PACKAGE_NAME/files" />//Don't forget to add package name here i.e. com.android.example
</paths>

Add this to you AndroidManifest.xml in application tag.

<provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="YOUR_APP_PACKAGE_NAME"////Don't forget to add package name here i.e. com.android.example
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/my_paths" />
    </provider>

Now you need permission to write file in storage,

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

After getting permission call this method to open camera

private void displayCamera() {
    File imagesFolder = new File(Environment
            .getExternalStorageDirectory(), getContext().getResources()
            .getString(R.string.app_name));
    try {
        if (!imagesFolder.exists()) {
            boolean isCreated = imagesFolder.mkdirs();
            if (!isCreated) {
                Toast.makeText(getContext(), R.string.str_storage_error, Toast.LENGTH_LONG).show();
                return;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
    String imageFileName = "IMG_" + timeStamp + "_";
    File storageDir = getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    try {
        File image = File.createTempFile(
                imageFileName,  /* prefix */
                ".jpg",  /* suffix */
                storageDir     /* directory */
        );
        Uri uri = FileProvider.getUriForFile(getContext(), getContext().getPackageName(), image);

            String imagePath=image.getAbsolutePath();//Store this path as globe variable

            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
            startActivityForResult(intent, Constants.CAMERA);

    } catch (ActivityNotFoundException | IOException e) {
        e.printStackTrace();
    }
}


@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
     if (resultCode == Activity.RESULT_OK) {
         //Here you need to show image 
         //if you want to show using glid then use

         Glide.with(this)
              .load("file://" + imagePath)//here you need image path which is stored in globel variable
              .apply(RequestOptions.circleCropTransform())
              .into(mBinder.ivDp);
     }
}

If you are know kotlin language please copy paste code in application. If you want to write in java just see logic.

On Camera Button Click:-

     /**
     * Handle camera button click
     */
    private fun onCameraButtonClick() {
        try {
            mPhotoFile = CommonUtils.createImageFile(this)
            // Continue only if the File was successfully created
            if (mPhotoFile != null) {
                dispatchTakePictureIntent(mPhotoFile!!)
            }
        } catch (ex: IOException) {
            // Error occurred while creating the File
            onError(R.string.some_error)
        }
    }

Create Image file : -

 /**
 * Create image file to save capture image
 * @return Image File
 */
@Throws(IOException::class)
fun createImageFile(context: Context): File {
    // Create an image file name
    val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
    val imageFileName = "JPEG_" + timeStamp + "_"
    val storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
    return File.createTempFile(
            imageFileName, /* prefix */
            ".jpg", /* suffix */
            storageDir      /* directory */
    )
}

After creating image file check weather is permission is grant or not:-

  /**
 * Launch camera application to take picture
 */
private fun dispatchTakePictureIntent(photoFile: File) {
    if (hasPermission(Manifest.permission.CAMERA) && hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
        val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
        // Ensure that there's a camera activity to handle the intent
        if (takePictureIntent.resolveActivity(this.packageManager) != null) {

            val photoURI = FileProvider.getUriForFile(this,
                    "your packege name.fileprovider",
                    photoFile)
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
            startActivityForResult(takePictureIntent, AppConstants.REQUEST_IMAGE_CAPTURE)

        }
    } else {
        requestPermissionsSafely(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA), AppConstants.REQUEST_CAMERA_PERMISSION_CODE)
    }
}

Handle Camera Result:-

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    if (resultCode == Activity.RESULT_OK) {
        when (requestCode) {
            AppConstants.REQUEST_IMAGE_CAPTURE -> {
                // Get the camera result
                mActivityEditProfileBinding.imgProfilePic.setImageBitmap(CommonUtils.getBitmapImageFromFilePath(mPhotoFile!!))

            }
            else -> super.onActivityResult(requestCode, resultCode, data)
        }
    }
}

Get bitmap from file:-

  /**
 * @return Bitmap from saved image file path
 */
fun getBitmapImageFromFilePath(file: File): Bitmap? {
    if (file.exists()) {
        val myBitmap = BitmapFactory.decodeFile(file.absolutePath)
        val ei = ExifInterface(file.absolutePath)
        val orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                ExifInterface.ORIENTATION_UNDEFINED)

        val rotatedBitmap: Bitmap?
        rotatedBitmap = when (orientation) {

            ExifInterface.ORIENTATION_ROTATE_90 -> rotateImage(myBitmap, 90.0f, file)

            ExifInterface.ORIENTATION_ROTATE_180 -> rotateImage(myBitmap, 180.0f, file)

            ExifInterface.ORIENTATION_ROTATE_270 -> rotateImage(myBitmap, 270.0f, file)

            ExifInterface.ORIENTATION_NORMAL -> myBitmap
            else -> myBitmap
        }
        return rotatedBitmap
    }
    return null
}

Paste into your manifest :-

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

Create a xml name folder in your res folder paste below code:-

    <?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path
        name="external_files"
        path="." />
</paths>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM