Say I have three activities A, B and C which are used in the following way. You start on activity A and press a button which takes you to B where you press another button that takes you to C. Now while on C you are done and want to go back to A. There are probably many ways of doing this, but I am interested in the difference between going back to A via an Intent vs using finish().
Using Intent:
Intent(this, A::class.java).also { startActivity(it) }
Using finish(): In order to properly end up back in A, I believe I would have to do something like this.
// Activity_B.kt
...
override fun onResume() {
super.onResume()
if(resumed > 0) { // resumed is "private var resumed: Int = 0"
// Next time we resume, we'll enter here.
// Specifically, we end up here after C calls finish()
finish() // This takes us back to activity A.
} else {
// End up here after first time A is created
resumed
}
}
// Activity_C.kt
...
finish() // This takes us back to Activity_B and onResume() is called
...
Using Intents we immediately end up in A while if we do it in the second way we have to pass back through B first. My question is whether one is more appropriate than the other? For some reason the second way using finish() feels more natural because we backtrack back by finishing up the use of activites while when using intents it feels like we're "leaving activites waiting and unfinished" in some sense. Is there actually a difference or are they equivalent in behaviour "behind the scenes"?
CodePudding user response:
If I understand your question, I think finish() just calls the finish() method for the current activity. if you want to go to a specific activity, intents are the best and appropriate way to go. with Flags of course.
I don't know why you need OnResume() for this.
usually better to use startActivity(intent); and then call finish(); so that the current activity doesn't stay in background. unless of course you want that.
ps. talking here from Java point of view. I don't know if its the same in Kotlin.
onButtonClick(View v){
Intent intent=new Intent(context,targetactivity.class);
// if you want put your Flags actions or Extras here...
//start target activity.
startActivity(intent);
// finish current activity
// this is just to finish the current activity and ha no control
// on where you end up.
finish()
}
and may be override onBackPressed()
CodePudding user response:
The primary difference is what you end up with in your back stack. If you go back to A
using an intent you will end up with a back stack of [A, B, C, A]
, which means if the user presses the back button on their phone after doing this, they will go back to C
. Pressing back again will then take them back to B
. Depending on what these activities are, this may or may not be desired behavior.
If you use finish()
the activities are removed from the back stack, so after going back to A
your back stack would not include B
and C
, it would just be [A]
However, you should use an onActivityResult
callback or just finish B before moving to C instead of relying on onResume
for that. Using onResume
would have unintended side effects, for example if the user minimized your app while on Activity B (e.g. to check their email or answer a call) - when they came back to your app it would call onResume
and trigger finish()
erroneously.
Method 1 - Activity Result Callback
The flow for this would be:
- Activity A starts activity B
- Activity B starts activity C using an appropriate
onActivityResult
callback. In this callback, activity B will callfinish()
when it is notified thatC
is finished. - When activity C is done, it sets its result status to complete (
RESULT_OK
) and callsfinish()
- which will notify activity B that it must also callfinish()
For example, these would be in Activity B:
// Activity B
var goToC = registerForActivityResult(StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
// This will be called when C is completed
finish();
}
}
private fun goToActivityC() {
val intent = Intent(this, ActivityC::class.java)
goToC.launch(intent)
}
And when activity C is done you would call this method to set its result and finish itself (taking the app back to B and immediately triggering the callback above). Note that if the user pressed back, the result wouldn't be set and they would just go back to B without triggering the callback.
// Activity C
private fun allDone() {
Intent data = Intent()
setResult(Activity.RESULT_OK, data)
finish()
}
Method 2 - Finish B before launching C
Another alternative to this would be to just finish B before you start C, so then Activity B would use
private fun goToActivityC() {
val intent = Intent(this, ActivityC::class.java)
startActivity(intent)
finish() // finish and remove B from the back stack
// back stack will now be [A, C]
}
and in Activity C
private fun allDone() {
finish() // finish and remove C from the back stack
// Will take you back to A and back stack will be just [A]
}
The main downside of this approach is that if the user presses back while on C they will go back to A, not B. This may not be intuitive behavior (really depends what these activities are).