6

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.

Ryan M
  • 18,333
  • 31
  • 67
  • 74
superchow
  • 61
  • 1
  • 1
  • 2
  • 1
    Does this answer your question? [How to replace startActivityForResult with Activity Result APIs?](https://stackoverflow.com/questions/61455381/how-to-replace-startactivityforresult-with-activity-result-apis) – Oguzhan Jul 16 '21 at 08:37
  • Hey try this hope it matches your question https://stackoverflow.com/questions/68268567/onactivityresult-is-deprecated-in-android-fragment/68269483#68269483 – Tippu Fisal Sheriff Jul 16 '21 at 11:45
  • I don't think those duplicates are quite on point - they don't describe how to avoid the error. I've tried to address that in my answer. – Ryan M Jul 17 '21 at 03:57

3 Answers3

10

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.

Ryan M
  • 18,333
  • 31
  • 67
  • 74
  • I am using what you suggested but the callback is not made the first time I grant it. I am using this for requestPermission(WRITE_...) in a DialogFragment and I want to write to a file right after I grant the permission. The second time I press the button the call back already receives granted and write immediately. – msc87 Jun 02 '22 at 11:43
  • @msc87 you'd have to ask a new question with a [mre]. If done correctly, it should work. – Ryan M Jun 02 '22 at 11:52
  • Thanks for replying. I asked a question [here](https://stackoverflow.com/questions/72476132/request-permission-to-write-in-dialogfragment-with-new-registerforactivityresult) – msc87 Jun 02 '22 at 12:18
2

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
        }
    }
}
Tippu Fisal Sheriff
  • 2,177
  • 11
  • 19
0

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();
    
Mary Jones
  • 99
  • 3