Structuring your Android activities

MVVM, Technical stuff, Work, Xamarin, XAML
5 Comments

In Android development, what XAML coders call “code behind” is stored in a class deriving from Activity. This is where you will handle the UI events, prepare the view, etc. Just like in XAML, the code you put there is less testable and less shareable but for view code, this is the place to do it. Of course if you use MVVM Light (or another MVVM approach), you reduce the amount of view code and some of the issues go away.

When you come from XAML, you notice how pampered we are by Microsoft. For example, if I add a UI element in the XAML and give it a name as shown below, the IDE will automatically generate a field in the code behind, so that I can interact with this element, for example by handling some events. This is super convenient. Of course if you don’t give a name to the element, no field is generated, and you cannot interact with the element (which is OK for most of the elements on the UI). You might wonder where the field gets generated, in fact it is hidden. To find it, you will need to dig a little.

TextBlock in XAML

<Grid>

    <TextBlock x:Name="MyTextBlock" />
        
</Grid>

To see the generated code, you need to click on the “Show All Files” button in the Solution Explorer. Then you can dive into the obj/Debug folder.

Show All Files button
2014-11-04_10-11-48

obj/Debug folder and generated files
2014-11-04_10-12-17

If you open this file, you will see some code looking like this:

Generated code parsing the XAML and defining fields

public partial class MainWindow : System.Windows.Window, System.Windows.Markup.IComponentConnector {
        
// [...]

    internal System.Windows.Controls.TextBlock MyTextBlock;
        
// [...]

    void System.Windows.Markup.IComponentConnector.Connect(int connectionId, object target) {
        switch (connectionId)
        {
        case 1:
        this.MyTextBlock = ((System.Windows.Controls.TextBlock)(target));
        return;
        }
        this._contentLoaded = true;
    }
}
}

Here you can see how the application is parsing the XAML and assigning an internal field for the MyTextBlock element. Most of the time, you don’t have to know about this, it is just available to you in the code behind.

The Android view

In Android, the markup language is called AXML. It is quite similar to XAML with enough differences to make it interesting ;) One of the main annoyance however is that named elements do not get a field in the “code behind” (the Activity). You need to add it manually. For example, the following AXML requires the following code in the MainActivity to access the MyTextView element:

AXML markup defining the UI

<TextView
    android:text="Text"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/MyTextView" />

Getting access to the element defined by the ID

FindViewById<TextView>(Resource.Id.MyTextView));

Ideally it would be nice if Xamarin was creating this code automatically when the AXML file is modified, just like the XAML tools are doing on the Windows side.

Since this is not the case however, MVVM Light is offering a code snippet to make things less annoying to write. After installing Version 5, you can follow these steps:

  • Add the element to the AXML view and give it an ID.
  • In the Activity code, place the cursor in the class, outside of any method.
  • Type the shortcut “mvvm”

MVVM Light code snippets
2014-11-16_11-31-37

  • Select the mvvmdroidelement snippet.
  • Replace the fields as shown here:

Snippet code getting access to the TextView

private TextView _myTextView;

public TextView MyTextView
{
    get
    {
        return _myTextView
                ?? (_myTextView = FindViewById<TextView>(Resource.Id.MyTextView));
    }
}

This code attempts to get the MyTextView element on demand and caches it to avoid the expensive interaction with the AXML parser. Having this annoying code stored as a code snippet in Visual Studio is a good step because it allows you to write less code. There is one more thing I like to do though:

Using partial classes for cleaner code

Here too, I draw from my experience in XAML. As we saw about, the generated code allowing access to named elements is placed in a partial class: Every code-behind file (MainWindows.xaml.cs for WPF, MainPage.xaml.cs for Windows Phone and Windows Store, etc) hosts a partial class. The other partial is located in the obj\Debug folder as shown above.

For my personal preference, the Android code getting access to an IDed element is something that should be hidden somehow. It is typical scaffolding code, and I like to store this code in a partial class that I rarely open. Just like in XAML the “hidden” partial class’ file is named MainWindow.g.i.cs, I also use a specific extension in Android and store my scaffolding code in a file named MainActivity.ui.cs.

Nesting the partial files

In addition to having a partial class for the plumbing code, I like to nest my MainActivity.ui.cs file within the MainActivity.cs file in the Solution Explorer. This is highly unnecessary and won’t bring any advantage in terms of performance or building your code, but it is just neater, and I am a neat guy.

Right now the process of nesting the files is manual, there is (as far as I know) no tool or menu allowing you to do that easily in the Solution Explorer directly. In a near future, I am hoping to release some project and item templates for Android which will make this process easier by providing “pre-wired” Activity templates. For now, you need to follow the manual steps below:

  • Right click on the project node in the Solution Explorer.
  • Select Unload Project from the context menu.
  • Right click again on the unloaded project node and select Edit [your project name].csproj.

2014-11-16_11-00-51
Editing the unloaded CSPROJ file

  • In the CSPROJ file, locate the node corresponding to the file you want to nest. It should look like this:
<Compile Include="MainActivity.ui.cs" />

Non-nested MainActitity.ui.cs file

  • Modify the XML markup as follows:

Nested MainActitity.ui.cs file

<Compile Include="MainActivity.ui.cs">
    <DependentUpon>MainActivity.cs</DependentUpon>
</Compile>
  • Right click on the unloaded project node again and select Reload [your project name].csproj.
  • Confirm that you want to save (if needed).

At this point, you will not see the MainActivity.ui.cs file anymore. It is nested under the MainActivity.cs file, as you can see if you expand this node in the Solution Explorer.

2014-11-16_11-11-05
Nested UI.CS file

In terms of code, the resulting activity is cleaner than before, with a clearly defined area where you can enter the binding and event handling code, and another clearly defined area where you can enter your scaffolding code.

“Main” MainActivity file with the bindings, event handlers, etc.

public partial class MainActivity
{
    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        // Set our view from the "main" layout resource
        SetContentView(Resource.Layout.Main);

        // Create your bindings here
        this.SetBinding(
            () => Vm.MyProperty,
            () => MyTextView.Text);
    }
}

“Scaffolding” code in the nested MainActivity.ui.cs

[Activity(
    Label = "My main page",
    MainLauncher = true,
    Icon = "@drawable/icon")]
public partial class MainActivity : Activity
{
    public MainViewModel Vm
    {
        get
        {
            return App.Locator.Main;
        }
    }

    private TextView _myTextView;

    public TextView MyTextView
    {
        get
        {
            return _myTextView
                    ?? (_myTextView = FindViewById<TextView>(Resource.Id.MyTextView));
        }
    }
}

Conclusion

In this article, I showed how I like to structure my Android applications’ views and isolate scaffolding code from the main code in which I define my bindings and my event handlers. I also showed how the MVVM Light “mvvmdroidelement” code snippet makes creating the scaffolding code easier, something that we have to do but don’t want to spend any unnecessary time on.

Finally, we talked about future plans to have MVVM Light project and item templates in Visual Studio to make these tasks easier. I hope that you are excited about cleaning your Xamarin code with these tips and tricks :)

Happy coding!
Laurent

GalaSoft Laurent Bugnion
Laurent Bugnion (GalaSoft)

Share on Facebook
 

5 Responses to “Structuring your Android activities”

  1. Corrado Cavalli Says:

    Regarding nesting: VSCommands extension for Visual Studio has a Group files feature that does exactly that (i use it often and works great)
    Regarding of missing of automatic generation of identifiers by the compiler, think the reason is that in Android you can ideally have separate .axml files associated to the same Activity (e.g Landscape vs Portrait) and is not guaranteed that both will contains the same named elements.

    Cheers

  2. lbugnion Says:

    Excellent feedback, thanks my friend

  3. Ben Says:

    Very cool that you can make this happen manually. With any luck, Xamarin.Forms will do this automatically someday. :)

  4. Michele Says:

    this is my resharper template to generate the scaffolding for a control
    private $TYPE$ $PrivateName$;

    public $TYPE$ $Name$
    {
    get
    {
    return $PrivateName$
    ?? ($PrivateName$ = FindViewById(Resource.Id.$id$));
    }
    }

    with rules that automatically set privatename and id based on name

  5. haider Says:

    Can you please post this code?

Leave a Reply