androidkotlinfileprovider

App suddenly crashes after taking a picture, rotate the screen and return to the activity


App suddenly crashes after taking a picture, rotate the screen and return to the activity. I’m making an Android app that need take a picture and store their route into a DB as String, I followed the official google tutorial (https://developer.android.com/training/camera/photobasics#kotlin) to do this without implement my own camera app. But I’m having an issue when I do the follow steps: • Open the activity that holds the logic to take the photo using the media dispatchTakePictureIntent() • Start the camera in portrait mode. • Rotate the screen to horizontal /camera to landscape mode. • Take the photo and do a tap on the “ok” button. • The app crashes.

But if don’t rotate the phone when the camera is open I can use the capture photo as I wish.

My code is this:

   override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        if(requestCode == CodigosDeSolicitud.ANADIR_FOTOGRAFIA && resultCode == Activity.RESULT_OK){
            setPic()
        }
    }

    @Throws(IOException::class)
    private fun createImageFile() : File{

        val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
        val storageDir : File = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
        return File.createTempFile(
                "JPEG_${timeStamp}_",
                ".jpg",
                storageDir
        ).apply {
            mCurrentPhotoPath = absolutePath
        }

    }

    private fun dispatchTakePicktureIntent(){
        Intent(MediaStore.ACTION_IMAGE_CAPTURE).also {takePictureIntent ->
            takePictureIntent.resolveActivity(packageManager)?.also {
                val photoFile : File? = try{
                    createImageFile()
                } catch (ex : IOException){
                    null
                }
                photoFile?.also {
                    val photoURI: Uri = FileProvider.getUriForFile(
                            this,
                            "com.kps.spart.android.fileprovider",
                            it
                    )
                    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
                    startActivityForResult(takePictureIntent, CodigosDeSolicitud.ANADIR_FOTOGRAFIA)
                }
            }

        }
    }

    private fun setPic(){
        val targetW: Int = iconoUsuarioIV.width
        val targetH: Int = iconoUsuarioIV.height

        val bmOptions = BitmapFactory.Options().apply {
            inJustDecodeBounds = true
            BitmapFactory.decodeFile(mCurrentPhotoPath,this)
            val photoW: Int = outWidth
            val photoH: Int = outHeight

            val scaleFactor : Int = Math.min(photoW / targetW, photoH / targetH)

            inJustDecodeBounds = false
            inSampleSize = scaleFactor
            inPurgeable = true
        }

        val exif = ExifInterface(mCurrentPhotoPath)
        val orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,ExifInterface.ORIENTATION_UNDEFINED)
        Toast.makeText(this@RegistrarUsuarioActivity,"Orientacion: " + orientation, Toast.LENGTH_SHORT).show()

        BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions)?.also { bitmap ->
            iconoUsuarioIV.setImageBitmap(bitmap)
        }

And my logcat gives me the next errors:

Caused by: java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1000, result=-1, data=null} to activity {com.kps.spart.moskimedicationreminder/com.kps.spart.moskimedicationreminder.RegistrarUsuarioActivity}: java.lang.ArithmeticException: divide by zero
    at android.app.ActivityThread.deliverResults(ActivityThread.java:4519)
    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3777)
    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3845) 
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3065) 
    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4950) 
    at android.app.ActivityThread.-wrap19(Unknown Source:0) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1730) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loop(Looper.java:164) 
    at android.app.ActivityThread.main(ActivityThread.java:7000) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:441) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1408) 
 Caused by: java.lang.ArithmeticException: divide by zero
    at com.kps.spart.moskimedicationreminder.RegistrarUsuarioActivity.setPic(RegistrarUsuarioActivity.kt:223)
    at com.kps.spart.moskimedicationreminder.RegistrarUsuarioActivity.onActivityResult(RegistrarUsuarioActivity.kt:170)
    at android.app.Activity.dispatchActivityResult(Activity.java:7630)
    at android.app.ActivityThread.deliverResults(ActivityThread.java:4515)
    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3777) 
    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3845) 
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3065) 
    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4950) 
    at android.app.ActivityThread.-wrap19(Unknown Source:0) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1730) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loop(Looper.java:164) 
    at android.app.ActivityThread.main(ActivityThread.java:7000) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:441) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1408) 

Using the interruption points I found that when I rotate the screen while taking the photo the activity is destroyed But why this happen if i'm not in that activity and how can I solve this problem?


Solution

  • I've stumbled upon this one myself (following the same guide). I know the question is old, but I'm posting the solution for any other that might come across it.

    The problem is in the onCreate method which is called twice (when you return to the activity after taking a picture, after device rotates). In order to avoid it, you should prevent the second call of dispatchTakePicktureIntent (which I'm guessing you do in your onCreate method).

    I've implemented it like this:

    class TakePhotoActivity : AppCompatActivity() {
    
        private val captureRequestCode = 1
        private val captureState = "capture_in_progress"
        private val capturePhotoPath = "capture_photo_path"
        private var photoPath: String? = null
        private var captureInProgress: Boolean = false
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_take_photo)
            captureInProgress = savedInstanceState?.getBoolean(captureState) ?: false
            photoPath = savedInstanceState?.getString(capturePhotoPath)
    
            if(!captureInProgress){
                captureInProgress = true
                dispatchTakePictureIntent()
            }
        }
    
        override fun onSaveInstanceState(outState: Bundle) {
            outState.putBoolean(captureState, captureInProgress)
            outState.putString(capturePhotoPath, photoPath)
            super.onSaveInstanceState(outState)
        }
    
        override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
            super.onActivityResult(requestCode, resultCode, data)
            if (requestCode == captureRequestCode && resultCode == RESULT_OK) {
                user_photo.adjustViewBounds = true
                val imgFile = File(photoPath ?: "")
    
                if (imgFile.exists()) {
                    val myBitmap = BitmapFactory.decodeFile(imgFile.absolutePath)
                    user_photo.setImageBitmap(myBitmap)
                    runImageLabelingOnCurrentPicture(myBitmap)
                }
                captureInProgress = false
            }
        }
    }
    

    You need to save the flag 'taking picture in process' into savedInstanceState and restore it if exists in the onCreate method. That is all.