Wednesday, October 2, 2013

Xamarin Android Activities and Intents

One thing that is really important to understand with Xamarin Android development (or just Android development in general) is how activities work and how to navigate between them.  The Xamarin site talks a little about this but it does not really dig deep into the different options for navigating between activities.  That explanation can be found here:

The most common way to navigate to a new activity is via the StartActivity command.  By default this will create a new activity on the stack.  The Main Activity in an application may create a Second Activity with the following command:

var secondActivity = new Intent(this, typeof(SecondActivity));

In this case the activity stack looks like this (please excuse the lack of cool graphics):

Second Activity (current)
Main Activity

If the second activity used the StartActivity command in the same way to try and reopen the Main Activity the call stack will look like this:

Main Activity (current)
Second Activity
Main Activity

It will not re-use the existing Main Activity, but it will create a new instance of the Main Activity.  If you press the back button that will pop the latest Main Activity off the stack and return you to the Second Activity but what if you wanted instead to have brought the original Main Activity back to the fore front without creating a new one?  In that case you could have reordered the activities in the activity stack to bring the Main Activity back to the front with the following command:
var mainIntent = new Intent(this, typeof(MainActivity));

If this were called from the Second Activity instead the activity stack would appear as so:

Main Activity (current)
Second Activity

It did not create a new instance of the Main Activity but the Second Activity didn't go away either.  Pressing the back button will now destroy the Main Activity and return to the Second Activity.

The Second Activity could also have just called Finish() instead.  That would have destroyed the Second Activity and returned to the Main Activity similar to what would have happened if the back button were pressed.

There are other options as well.  What if the Main Activity wanted to create the Second Activity and return some information back to the Main Activity without the Second Activity staying on the activity stack?  For this you can use StartActivityForResult:
var secondActivity = new Intent(this, typeof(SecondActivity));
StartActivityForResult(secondActivity, 1);

The second parameter on the StartActivityForResult is a unique identifier that you can use later to identify which activity it was that is returning to the Main Activity.  As you would expect once the Second Activity is created the activity stack would look like this:

Second Activity (current)
Main Activity

It is important to note that the second activity is not a modal window.  It can in turn just re-create a new instance of the Main Activity or a Third Activity or anything else.  When the Second Activity is done you can send some information back to the Main Activity along with if the Second Activity completed successfully.  To do this you can use code similar to this:
var myIntent = new Intent(this, typeof(MainActivity));
myIntent.PutExtra("My Key", "The data I want to send back");
this.SetResult(Result.Ok, myIntent);

This will not create a new instance of the Main Activity but return to the existing one.  The intent allows you to send information back to the Main Activity from the Second Activity.  In this case the PutExtra allows you to add key value pairs of information, strings, integers, binary data, etc.  It also uses the SetResult command to indicate that the activity completed successfully.

The question is, now how does the Main Activity use the information passed back from the Second Activity?  That's what the OnActivityResult event is for.  You can implement this event on the Main Activity and it will fire when the Second Activity is finished.

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
    base.OnActivityResult(requestCode, resultCode, data);
    var returnString = data.GetStringExtra("My Key");
    var result = resultCode;

It is important to note that the OnActivityResult event will fire on the Main Activity before the OnRestart event, followed by the OnStart and OnResume events.

If the intent were not passed along to the SetResult command in the Second Activity, the data parameter would be null.  Since it was, we can use functions such as GetStringExtra to retrieve the data that was set in the Second Activity.  The requestCode should have a value of 1 in this case, the value we set when we created the intent to create the Second Activity. 

The resultCode parameter can also be used to tell if the activity was ended successfully.  If the back button was pressed the value of the resultCode would be Result.Cancelled.  Also once the Finish method is called in the Second Activity it is unloaded and removed from the activity stack as you would expect.

I hope this has helped some of you understand how to navigate between activities in Xamarin Android.

No comments:

Post a Comment