superchow
superchow

Reputation: 101

How to use registerForActivityResult correctly? Getting "LifecycleOwners must call register before they are STARTED"

I use registerForActivityResult just like :

package com.example.livedata

import android.Manifest
import android.app.Activity
import android.app.AlertDialog
import android.app.Dialog
import android.content.ActivityNotFoundException
import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
import android.view.View
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import com.example.livedata.databinding.ActivityAddBinding
import com.example.livedata.databinding.DialogCustomImageSelectionBinding


class AddActivity : AppCompatActivity(), View.OnClickListener {
    private lateinit var binding: ActivityAddBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityAddBinding.inflate(layoutInflater)
        setContentView(binding.root)
        setupActionBar()

        binding.photoAdd.setOnClickListener(this)
    }

    private fun setupActionBar() {
        setSupportActionBar(binding.toolbar)
        supportActionBar?.setDisplayHomeAsUpEnabled(true)
        binding.toolbar.setNavigationOnClickListener { onBackPressed() }
    }

    override fun onClick(v: View?) {
        if (v != null) {
            when (v.id) {
                R.id.photo_add -> {
                    imageDialog()
                    return
                }
            }
        }
    }

    private fun imageDialog() {
        val dialog = Dialog(this)
        val dialogBinding: DialogCustomImageSelectionBinding =
            DialogCustomImageSelectionBinding.inflate(layoutInflater)
        dialog.setContentView(dialogBinding.root)
        dialog.show()

        dialogBinding.impCamera.setOnClickListener {
            registerForActivityResult(ActivityResultContracts.TakePicturePreview()) {
                if (it != null) {
                    Toast.makeText(this@AddActivity, "TakePicturePreview", Toast.LENGTH_SHORT).show()
                }
            }.launch(null).apply { arrayOf(
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.CAMERA) }
            dialog.dismiss()
        }

    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == 1 && resultCode == Activity.RESULT_OK) {
            data?.let {
                val bp = data.getParcelableExtra<Bitmap>("data")
                binding.imageView.setImageBitmap(bp)

            }
        }
    }

    private fun showPermissions() {
        AlertDialog.Builder(this).setMessage("Applay Permissions!")
            .setPositiveButton("Go to Settings") { _, _ ->
                try {
                    val intel = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                    val uri = Uri.fromParts("package", packageName, null)
                    intel.data = uri
                    startActivity(intel)
                } catch (e: ActivityNotFoundException) {
                    e.printStackTrace()
                }
            }.setNegativeButton("Cancel") { dialog, _ ->
                dialog.dismiss()
            }.show()
    }
}

But it do not work and throw an exception here :

2021-07-16 15:38:50.472 29885-29885/com.example.livedata E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.livedata, PID: 29885
    java.lang.IllegalStateException: LifecycleOwner com.example.livedata.AddActivity@9fc53b9 is attempting to register while current state is RESUMED. LifecycleOwners must call register before they are STARTED.
        at androidx.activity.result.ActivityResultRegistry.register(ActivityResultRegistry.java:123)
        at androidx.activity.ComponentActivity.registerForActivityResult(ComponentActivity.java:659)
        at androidx.activity.ComponentActivity.registerForActivityResult(ComponentActivity.java:668)
        at com.example.livedata.AddActivity.imageDialog$lambda-3(AddActivity.kt:68)
        at com.example.livedata.AddActivity.lambda$N7K_EbTML-ycmUwpA7-i8b_L-Sw(Unknown Source:0)
        at com.example.livedata.-$$Lambda$AddActivity$N7K_EbTML-ycmUwpA7-i8b_L-Sw.onClick(Unknown Source:4)
        at android.view.View.performClick(View.java:7281)
        at android.view.View.performClickInternal(View.java:7255)
        at android.view.View.access$3600(View.java:828)
        at android.view.View$PerformClick.run(View.java:27925)
        at android.os.Handler.handleCallback(Handler.java:900)
        at android.os.Handler.dispatchMessage(Handler.java:103)
        at android.os.Looper.loop(Looper.java:219)
        at android.app.ActivityThread.main(ActivityThread.java:8393)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1055)
2021-07-16 15:38:50.539 1689-2062/? E/InputDispatcher: channel 'ba7a009 com.example.livedata/com.example.livedata.AddActivity (server)' ~ Channel is unrecoverably broken and will be disposed!

How can I use the registerForActivityResult to accomplish this task instead of the deprecated method? All help is much appreciated.

Upvotes: 10

Views: 33256

Answers (3)

Mary Jones
Mary Jones

Reputation: 125

Here is the Java Code version - Using ActivityResultLauncher

  • In Activity A : Launch Activity B, eg: if you using a Button View onSetClickListener

Button btn = findViewById(enter button view id name here)

  • Call the btn.setOnClickListener and place this code in the onClick()-method of the button

    mStartForResult.launch(new Intent(MainActivity.this, DestinationActivity.class));

  • Call ActivityResultLauncher API and retrieve the result from Activity B using the Intent & the ResultCode.

`

ActivityResultLauncher<Intent>mStartForResult = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),new ActivityResultCallback<ActivityResult>()

{ 
 
if(result.getResultCode()== Activity.RESULT_OK) 

{
   

            
           Intent intent = result.getData();
        
            'enter your code here'


}
});
  • You may want to use shared preferences to save and retrieve data from ActivityB to A

  • In Activity B: Call the btn.setOnClickListener and place this code in the onClick()-method of the button:

        `Intent intent = new  Intent(DestinationActivity.this,MainActivity.class);`
     intent.putExtra(EXTRA, `enter your input(int or String) here`);
     setResult(RESULT_OK, intent);
     finish();
    

Upvotes: 1

Ryan M
Ryan M

Reputation: 20197

You're trying to call registerForActivityResult in a click listener. That's not going to work, because your Activity might be destroyed and recreated before the result is delivered. The recreated Activity won't have been registered to receive the result, because it only registers when you click the button, and the button was only clicked in the original Activity.

To fix this, you need to call registerForActivityResult unconditionally and store the result in a variable:

class MyActivity : AppCompatActivity() {
    private val activityLauncher = registerForActivityResult(...

That way, the recreated Activity will be registered to receive the result. Then use that activityLauncher variable to launch it from the button click listener.

For more information, see the official guide.

Upvotes: 14

Tippu Fisal Sheriff
Tippu Fisal Sheriff

Reputation: 2846

Kotlin - Below code instead of startActivityForResult deprecation this method gives the result itself and returns a value.

val resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
    when (result.resultCode) {
        Activity.RESULT_OK -> {
            // logic
        }
        else -> {
            // logic
        }
    }
}

Upvotes: 2

Related Questions