I have a main activity which serves as an entry point to call different activities, depending on condition. Among others, I use Firebase Auth to manage user sign in:
startActivityForResult(
AuthUI.getInstance().createSignInIntentBuilder()
.setAvailableProviders(providers)
.build(),
RC_SIGN_IN)
I overwrite onActivityResult()
to distinguish the returned intent/data, for example:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
REQUEST_CODE_1 -> {
// update UI and stuff
}
RC_SIGN_IN -> {
// check Firebase log in
}
// ...
}
}
With the Activity Result APIs which is strongly recommended by the documentation, I get that I should make prepareCall()
before ActivityResultLauncher
and to make sure the activity is in created state when I launch, but I still don't understand how to handle multiple activity results gracefully (at least, in one place) like in onActivityResult()
.
Looking at this article, it seems I need to implement multiple child inner classes of ActivityResultContract
type (therefore multiple prepareCall()
's?), because they are suppose to be different contracts, am I correct? Can someone please show me some skeleton example that mirrors the above onActivityResult()
logic?
But recently startActivityForResult() method is deprecated in AndroidX. Android came up with ActivityResultCallback (also called Activity Results API) as an alternative for it.
In this article, we will discuss the Activity Result API, an alternative to the deprecated startActivityForResult + onActivityResult methods. We will use Kotlin in this article for the code samples. Android introduced the Activity Result APIs as a major change in the androidx. activity:activity:1.2.
From now, startActivityForResult() has been deprecated so use new method instead of that.
First you use startActivityForResult() with parameters in the first Activity and if you want to send data from the second Activity to first Activity then pass the value using Intent with the setResult() method and get that data inside the onActivityResult() method in the first Activity .
You can call as many Activities for result as you wish and have separate callback for each:
val startForResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult())
{ result: ActivityResult ->
if (result.resultCode == Activity.RESULT_OK) {
// you will get result here in result.data
}
}
}
startForResult.launch(Intent(activity, CameraCaptureActivity::class.java))
You just need to specify Activity class - CameraCaptureActivity::class.java
Update:
The prepareCall() method has been renamed to registerForActivityResult() in Activity 1.2.0-alpha04 and Fragment 1.3.0-alpha04. And it should be startForResult.launch(...) in the last line
Thanks Rafael Tavares for update
From now, startActivityForResult()
has been deprecated so use new method instead of that.
Example
public void openActivityForResult() {
//Instead of startActivityForResult use this one
Intent intent = new Intent(this,OtherActivity.class);
someActivityResultLauncher.launch(intent);
}
//Instead of onActivityResult() method use this one
ActivityResultLauncher<Intent> someActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
// Here, no request code
Intent data = result.getData();
doSomeOperations();
}
}
});
First, don’t forget to add this to your Gradle dependency
implementation 'androidx.activity:activity-ktx:1.2.0-alpha05'
implementation 'androidx.fragment:fragment-ktx:1.3.0-alpha05'
Second, create your result contract by extending an abstract class called ActivityResultContract<I, O>
. I mean the type of input and O means the type of output. And then you only need to override 2 methods
class PostActivityContract : ActivityResultContract<Int, String?>() {
override fun createIntent(context: Context, input: Int): Intent {
return Intent(context, PostActivity::class.java).apply {
putExtra(PostActivity.ID, postId)
}
}
override fun parseResult(resultCode: Int, intent: Intent?): String? {
val data = intent?.getStringExtra(PostActivity.TITLE)
return if (resultCode == Activity.RESULT_OK && data != null) data
else null
}
}
And finally, the last step is registering the contract to Activity
. You need to pass your custom contract and callback into registerForActivityResult
.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
start_activity_contract.setOnClickListener {
openPostActivityCustom.launch(1)
}
}
// Custom activity result contract
private val openPostActivityCustom =
registerForActivityResult(PostActivityContract()) { result ->
// parseResult will return this as string?
if (result != null) toast("Result : $result")
else toast("No Result")
}
}
For More info check this Post
In this case, what was returned by AuthUI was already an Intent, so, we use it like in the example below.
private val startForResult =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
when(result.resultCode){
RESULT_OK -> {
val intent = result.data
// Handle the Intent...
mUser = FirebaseAuth.getInstance().currentUser
}
RESULT_CANCELED -> {
} else -> {
} }
}
start the activity from anywhere (for example on button click) using:
AuthUI.getInstance().createSignInIntentBuilder().setAvailableProviders(providers)
.build().apply {
startForResult.launch(this)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With