Different XAML layouts for different device orientations in Xamarin.Forms

In case you’ve been wondering how to achieve different XAML layouts for different device orientation with Xamarin.Forms (just Forms from now), here is a solution. The thing is that there is currently no support for this. There is support for different layout when it comes Phone vs Tablet (OnIdiom<T>) or when it comes to different OS (OnPlatform<T>) but the thing is that these guys are static. They do their work once and that’s it. They won’t react to changes and it makes sense, since underlying OS or device type don’t change during runtime.

So something different is need. But before I even start with the XAML there is an important part that has to be done – getting the current orientation, or better, rotation at the Portable Class Library level. It is a twofold solution.

Here is code that exists in PCL project and isn’t OS specific.

public enum Rotation
{
    Rotation0,
    Rotation90,
    Rotation180,
    Rotation270
}
public static class Orientation
{
    private static Rotation rotation;
    public static EventHandler RotationChanged;
    public static Rotation Rotation
    {
        get
        {
            return rotation;
        }
        set
        {
            if (Rotation != value)
            {
                rotation = value;
                OnRotationChanged();
            }
        }
    }

    public static bool IsLandscape
    {
        get
        {
            return Rotation == Rotation.Rotation90 
                || Rotation == Rotation.Rotation270;
        }
    }

    private static void OnRotationChanged()
    {
        if (RotationChanged != null)
            RotationChanged(null, EventArgs.Empty);
    }
}

And here is the OS specific part where you set the orientation.

Android version:

public class MainActivity : AndroidActivity
{
    protected override void OnCreate (Bundle bundle)
    {
        UpdateCurrentRotation();
        base.OnCreate (bundle);

        Xamarin.Forms.Forms.Init (this, bundle);

        SetPage (App.GetMainPage ());
    }

    public override void OnConfigurationChanged(Android.Content.Res.Configuration newConfig)
    {
        base.OnConfigurationChanged(newConfig);
        UpdateCurrentRotation();
    }

    private void UpdateCurrentRotation()
    {
        switch (WindowManager.DefaultDisplay.Rotation)
        {
            case  SurfaceOrientation.Rotation0:
                Orientation.Rotation = Rotation.Rotation0;
                break;
            case SurfaceOrientation.Rotation90:
                Orientation.Rotation = Rotation.Rotation90;
                break;
            case SurfaceOrientation.Rotation180:
                Orientation.Rotation = Rotation.Rotation180;
                break;
            case SurfaceOrientation.Rotation270:
                Orientation.Rotation = Rotation.Rotation270;
                break;
        }
    }
}

Windows Phone version (note that you have to set SupportedOrientations="PortraitOrLandscape" in your MainPage.xaml to enable rotation of the page):

public partial class MainPage : PhoneApplicationPage
{
    public MainPage()
    {
        InitializeComponent();
        UpdateRotation();
        Forms.Init();
        Content = App16.App.GetMainPage().ConvertPageToUIElement(this);
    }

    private void UpdateRotation()
    {
        if ((Orientation & PageOrientation.PortraitUp) 
== PageOrientation.PortraitUp) App16.Orientation.Rotation = Rotation.Rotation0; else if ((Orientation & PageOrientation.PortraitDown)
== PageOrientation.PortraitDown) App16.Orientation.Rotation = Rotation.Rotation180; else if ((Orientation & PageOrientation.LandscapeLeft)
== PageOrientation.LandscapeLeft) App16.Orientation.Rotation = Rotation.Rotation90; else App16.Orientation.Rotation = Rotation.Rotation270; } protected override void OnOrientationChanged
(OrientationChangedEventArgs e) { UpdateRotation(); base.OnOrientationChanged(e); } }

Sadly I have no iOS device at this time, but it should be pretty easy to support it as well.

At the beginning of the page/activity and each time orientation changes the current rotation is sent to Orientation class in PCL.

At this point we have the rotation information and event RotationChanges that notifies about changes in rotation. Now this information can be used to achieve the dynamic layout changes.

For that purpose I’ll use a Grid ContentView derived class that can be nicely used with XAML.

public class Rotational: ContentView
{
    public View Landscape { get; set; }
    public View Portrait { get; set; }
    public string LandscapeType { get; set; }
    public string PortraitType { get; set; }
    private bool isPortrait;

    protected override void OnParentSet()
    {
        base.OnParentSet();
        VisualElement view = ParentView;
        while (!(view is Page))
        {
            view = view.ParentView;
        }
        Page page = (Page)view;
        page.Disappearing += page_Disappearing;
        page.Appearing += page_Appearing;
    }

    void page_Appearing(object sender, EventArgs e)
    {
        Orientation.RotationChanged += CurrentOrientation_Changed;
        Update();
    }

    private void CurrentOrientation_Changed(object sender, EventArgs e)
    {
        Update(); 
    }

    void page_Disappearing(object sender, EventArgs e)
    {
        Orientation.RotationChanged -= CurrentOrientation_Changed;   
    }

    private void Update()
    {
        if (Content == null || Orientation.IsLandscape && isPortrait ||
            !Orientation.IsLandscape && !isPortrait)
        {
            Children.Clear();
            if (RhOrientation.IsLandscape)
{
isPortrait = false;
if (Landscape != null)
{
Content = Landscape;
}
else
{
View child = FindContentView(LandscapeType);
Content = child;
}
}
else
{
isPortrait = true;
if (Portrait != null)
{
Content = Portrait;
}
else
{
View child = FindContentView(PortraitType);
Content = child;
}
} } } private View FindContentView(string contentViewName) { var query = from t in GetType().GetTypeInfo().Assembly.DefinedTypes where t.IsClass && !t.IsAbstract && t.IsSubclassOf(typeof(ContentView)) && t.Name == contentViewName select t; var contentViewTypeInfo = query.SingleOrDefault(); if (contentViewTypeInfo != null) { ContentView page = (ContentView)Activator.CreateInstance
(contentViewTypeInfo.AsType()); return view; } else return null; } }

The class is named Rotational and defines four properties: Portrait, PortraitPage, Landscape and LandscapePage. Portrait and Landscape are of type View and you can store View derived classes that would appear based on orientation. Here is an example:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                       xmlns:v="clr-namespace:App16;assembly=App16"
                       x:Class="App16.TestPage">
  <v:Rotational>
    <v:Rotational.Landscape>
      <StackLayout Orientation="Vertical">
        <Label Text="Landscape" HorizontalOptions="Center" />
      </StackLayout>
    </v:Rotational.Landscape>
    <v:Rotational.Portrait>
      <StackLayout Orientation="Vertical">
        <Label Text="Portrait" HorizontalOptions="Center" />
      </StackLayout>
    </v:Rotational.Portrait>
  </v:Rotational>
</ContentPage>

Note that namespace declaration is required (xmlns:v="clr-namespace:App16;assembly=App16"). The above definition will show a label saying Portrait or Landscape, depending on device rotation and will change dynamically. The drawbacks of this approach are that both configurations are in-memory and the page might become a bit bloated.

Hence the second pair of properties: PortraitPage and LandscapePage. These are of string type and allow to enter the page class names the content of which will be used dynamically. Here is an example:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:v="clr-namespace:App16;assembly=App16"
                       x:Class="App16.TestPage">
  <v:Rotational PortraitType="PortraitTestContent" 
LandscapeType="LandscapeTestContent" /> </ContentPage>

Additional two pages are required (PortraitTestContent.xaml and LandscapeTestContent.xaml):

<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
                       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                       x:Class="App16.PortraitTestPage">
    <Label Text="Portrait test" VerticalOptions="Center" 
HorizontalOptions="Center" /> </ContentView> ... <ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="App16.LandscapeTestPage"> <Label Text="Landscape Test" VerticalOptions="Center"
HorizontalOptions="Center" /> </ContentView>

The pages are found using reflection and based on their names (no namespace is used).

This method is more memory efficient since it loads required content on demand and discards it afterwards. On the other side it is slower due to the loading of the page.

So, here you have it. What do you think? Is there a better way?

The sample is attached.

Rotational.zip (77.2KB)

Update 1: Instead of dynamically loading ContentPage and then using its content, ContentView should be used (it is XAML supported). That'd be a change in FindPageElement method to FindContentView.
Update 2: Changed base type for Rotational from Grid to ContentView.

Note: sample hasn't been updated from original version.

An alpha version of memory profiler for Xamarin Android

Memory profiling is one of the pillars of a good application. Even more important is on mobile devices since memory is usually scarce there. But sadly, there is no memory profiler for Xamarin Android development. Actually there is some raw support but lacks UI and friendliness. Hence I’ve built my own memory profiler.

This is an alpha quality version.

How it works

Since version 4.14 Xamarin has a (not) very visible support for memory profiling. But even with this support it isn’t easy to profile. With each garbage collection a log file is written on the device containing all the relevant data in a text format. Note that once you turn profiling on with

adb shell setprop debug.mono.profile log:heapshot

This setting is global and it works on all Xamarin apps on the device. Remember to turn it off afterwards if you don’t need it anymore to avoid, I guess, a huge performance hit.

There are two problems with the existing support here:

  • hard to trigger a garbage collection manually
  • hard to analyze data

My solution tackles both problems. The solution is divided into two parts.

Server side

The library available through NuGet does two things:

  • broadcasts its presence through UDP
  • allows triggering garbage collection from client

The library supports API Level 4 (Xamarin v1.6) and above.

Here is the NuGet package URL. You can also install it using this Package Manager Console command:

Install-Package RhMemProfiler.Server –Pre

The package is marked as prerelease and it won’t appear in NuGet Package manager if it isn’t set for Include Prerelease.

Once package has been added go ahead and create a global variable of type RhMemProfiler.Server.Beacon and initialize it with a friendly name and package name, like:

RhMemProfiler.Server.Beacon beacon;
….
beacon.Start("your friendly name", PackageName);

PackageName is the name of your package and it is ContextWrapper’s property.

Client side

This is a Windows application distributed through ClickOnce. After installation you’ll be prompted to open the firewall for the application. This is required since it, well, uses UDP and TCP to communicate with the server side.

profilerPrivate networks access is enough unless your mobile device is running on public network.

Once that is done you’ll be presented with a main window:

profiler

If your application on mobile device/emulator is running then you’ll see at least one option (one per IP on the device) in the combo box left of Connect button. That list contains friendly name (used when initializing on server) and its IP address. Pick any of them (IP doesn’t matter at this time). Hit Connect button.

If connection is successful you’ll see Conncted text in bottom left corner. If this is the first time you are connecting and/or memory profiling isn’t enabled yet on the device then you’ll be presented the Enable Profiling button, like:

enableprof

Enable profiling, restart mobile device application, disconnect, connect again and your are good to start memory profiling:

enableprof

Once there were at least two garbage collections and a snapshot has been taken afterwards you are able to compare them by selecting start and end version.

Collect Garbage … forces garbage collection on the mobile device
Snapshot … collects memory profiling log file from the device
Disable profiling … disables profiling on the device (profiling is per device, not per application – it affects all Xamarin apps on that device)
Only with source … shows only types from your package
Group panel … lets you group columns
Start and End … memory profile versions to compare to

Test

Imagine I have a class

public class MemLeak
{
    public string Value;
}

and a list of these somewhere defined. If I do a garbage collection before, when list is empty, and after one instance of MemLeak has been added I’ll see something like this when comparing before and after:

leak

It is pretty much obvious that the count of MemLeak instances increased by 1 and there are total of two instances of it around (actually I created one before that’s why there are two of them).

Memory profiling strategy

Memory profiling works by comparing state before and after. Usually a garbage collection is taken before some action and after that action. If the number of some instance increased without a valid reason it means that the application is leaking memory. Professional memory profilers help you even pinpointing the source of the leaks, however in our case, Xamarin doesn’t have that data available through this strategy.

Known limitations

  • ADB has to be in the path.
  • Only one device or emulator can be connected to the computer at the same time (the combo lets you pick the application but not the IP)

Final words

This is an alpha release, so be gentle with it and do not complain if your computer explodes because of it. It is something I wanted to release even at this stage for you to play with. It is actually pretty functional. So, feedback is appreciated and so are questions but I don’t guarantee anything, the development is done in my spare time (like that there is any Smile) for now. Hope you’ll find it useful.

Troubleshooting memory leaks in Xamarin.Android

I was testing an application I am building with Xamarin/Android. One of the tests was rotating the device while Google Maps fragment being shown. By default each time the orientation changes the activity and its views/fragments are recreated. IOW it is a good test for possible memory leaks because the recreation can be frequent.

I was quite surprised seeing a huge memory increase each time. Those eventually lead to an OutOfMemory in Java stack somewhere in Google Maps. After double checking that managed Xamarin code wasn’t leaking (i.e. retaining the said fragment somehow) anything I was starting to wonder whether Google Maps fragment is leaking internally. Perhaps only when combined with Xamarin. That’d be odd but not impossible.

Thus I started Android Studio and crafted a repro in pure Java. It wasn’t leaking. Thus it must have something to do with Xamarin. But what? Xamarin is providing a component to Google Maps (.net wrapping). Is it possible that there is a problem? Switching back to Xamarin and a few more tests later I couldn’t create a non leaking version. No matter what I did I still got leaks.

Suspecting a problem within Xamarin somewhere I decided to report a bug to bugzilla (Xamarin’s bug reporting web, not support) about it and mail a question to Xamarin support. The Jonathan Pryor’s response on bugzilla was lightning fast. In an hour or so he solved the mystery. The response from official support line was fast as well. (kudos to Xamarin on both).

It turns out that I was bitten with unmanaged memory pressure issue. Actually with unmanaged managed memory pressure issue. The thing is that Xamain/.net doesn’t know anything about unmanaged memory consumption. This is well known to .net developers, or at least, it should be. So, if you allocate a huge unmanaged piece of memory the .net won’t know about its size and won’t fire garbage collection automatically when it is released even it you are running low on memory (there are ways to let it know the memory consumption but that isn’t automatic). That’s usually valid for native code. But in the case of Xamarin, Java part is also unmanaged code to Xamarin (albeit Java is managed, but managed within Java with its own garbage collector).

Each time the Google Maps fragment was created and destroyed Xamarin created and “released” a single reference to maps fragment. By released I mean it was referenced from anywhere anymore and thus available for garbage collection by Xamarin garbage collector. But since .net saw only few bytes in that reference (which in turn referenced a ton of Java objects) it didn’t fire garbage collection automatically (and Java garbage collector couldn’t reclaim the memory because it was referenced by Xamarin) thus memory usage was increasing by huge steps. Strictly speaking this wasn’t a memory leak because all the memory would be reclaimed eventually - when garbage collection would run.

And that’s exactly how I solved it – I now run a manual garbage collection at least upon fragment creation (to reclaim the memory used by previous one). Problem solved. The bottom line is that you might run manual garbage collection after releasing a reference to Java object which internally uses plenty of memory. Also, calling Dispose on Xamarin objects helps (they might release reference to Java’s counterpart). In my case I couldn’t call Dispose because my fragment was created by layout inflation (actually I guess, I could by obtaining a reference to it, but that wasn’t obvious nor it might not help).

Here is more about Xamarin Garbage Collection.

Just developing for Windows 8 Store gives your privacy a funeral

I was poking around with excellent MonoGame framework by creating a simple game, or better, starting to create a simple game. So far I’ve spent a day to build some infrastructure from scratch and I am able to show a main screen with simple menu items. Nothing really ground-breaking.

The aspect I am most interested right now is cross platform development with MonoGame. Hence my simple game is built with cross platform support from beginning. Main development target is Windows 7 x64 because it is the easiest to debug the application on. I’ve ported the game successfully to Android as well by using Mono For Android – tested on both emulator and my Google Nexus phone. Port means just creating a bootstraper (an Android app that launches the game within an activity) and linking the sources to Mono For Android projects (here Project Linker comes to great help, though shame that Microsoft Patterns And Practices team seemingly abandoned it).

 

 

Windows Phone 8 emulator requirements are insane

Next I wanted to port it to Windows Phone 8 since its SDK is fresh from the oven and MonoGame supports it (not sure at what stage the support is). However, Windows Phone 8 SDK emulator requirements are just too much: Visual Studio 2012, Windows 8 Pro, 4GB RAM, and CPU with SLAT support to run the emulator which in turn runs on Hyper-V. I don’t have a Windows Phone 8 device so I wanted to give the emulator a test run. I have Windows 8 Pro on my laptop but, albeit perfectly functional, the CPU doesn’t feature SLAT. SLAT is required by Hyper-V on client versions of Windows 8. The interesting fact is that VMWare Workstation runs perfectly well without or with SLAT. Be also aware that VMWare Workstation and Hyper-V on Windows 8 won't coexist peacefully - Workstation will work only when Hyper-V feature isn't present. The bottom line is that the Windows Phone 8 emulator won’t run on my laptop. I could run it on my workstation but I haven’t migrated to Windows 8 at this time.

Windows 8 development license isn’t something for privacy consciousness

Next I wanted to run a Metro aka Windows Store Apps version of my game. Those should run just fine on my laptop. I started by creating a new Windows Store application and Visual Studio 2012 immediately notified me that I need a developer license for Windows 8 which is free. But reading its privacy statement made me wonder.


When you request a developer license, Microsoft collects information about your PC and the apps installed on it. This information includes your PC’s name, manufacturer, and model; your IP address; a unique identifier generated based on your PC’s hardware configuration; and the edition of Windows you’re using.
….
Microsoft may access or disclose information about you, including the content of your communications, in order to: (a) comply with the law or respond to lawful requests or legal process; (b) protect the rights or property of Microsoft or our customers, including the enforcement of our agreements or policies governing your use of the services; or (c) act on a good faith belief that such access or disclosure is necessary to protect the personal safety of Microsoft employees, customers, or the public. We may also disclose personal information as part of a corporate transaction such as a merger or sale of assets.

Remember, I wanted to test my game locally. And for that I’d need to send all sort of data to Microsoft? What the heck? Furthermore those legal obligations are really flexible. Not that I have anything to hide or against Microsoft but still why do I have to disclose installed applications on my computer and such? Note that I wouldn’t send my data to any company just to test an application on the local machine. So, for the time being, I will skip Windows Store App version as well.

Progress so far:

  • Windows Desktop [checked]
  • Android [checked]
  • Windows Phone 8 [unknown]
  • Windows Store App [unknown]
  • Windows Phone 7 [unknown,soon]

There is only one platform left to try – Windows Phone 7 where I don’t foresee any problems, just didn’t have time yet.

Writing to SD card and notifying outside world of changes

When writing a logging part of an application (Mono For Android/Visual Studio) I got some, seemingly, weird Android behaviour. Since my application transmits large strings over the net I wanted to have a history of these so I can check them out. I could do it with a simple string visualizer but the thing is that Mono For Android isn’t supporting any visualizer in Visual Studio at all – they are just not there. So I’ve decided to write those strings to a SD card in a folder accessible to Windows Explorer. Which is a better option anyway, as I could manipulate those later.

Here is the (simplified) code I use to write these to SD card

string path = Path.Combine(Context.GetExternalFilesDir(null), "file.txt");
File.WriteAllText(path, "large text here");

And I get a nice file in /Android/data/[package]/files. That’s all fine. However, Windows Explorer is unaware of newly created file at all. The file is there it just doesn’t see it. Looks like the problem is that Android (tested on two devices) doesn’t notify the outside world about the file system changes. Instead one has to do it manually. But how? AFAIK it can’t be done from within Windows Explorer.

After some googling I’ve found this stackoverflow thread. I’ve ported the MediaScannerConnection solution to C#.

public class SingleMediaScanner : Java.Lang.Object, MediaScannerConnection.IMediaScannerConnectionClient
{
    private MediaScannerConnection connection;
    private string file;

    public SingleMediaScanner(Context context, string file)
    {
        connection = new MediaScannerConnection(context, this);
        this.file = file;
    }

    public void Connect()
    {
        connection.Connect();
    }

    public void OnMediaScannerConnected()
    {
        connection.ScanFile(file, null);
    }

    public void OnScanCompleted(string path, Android.Net.Uri uri)
    {
        connection.Disconnect();
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
            connection.Dispose();
        base.Dispose(disposing);
    }

    public static void NotifyFile(Context context, string file)
    {
        SingleMediaScanner scanner = new SingleMediaScanner(context, file);
        scanner.Connect();
    }
}

One would call SingleMediaScanner.NotifyFile(Context, “FILEPATH”) to let the outside world of the changes to the file.

Not sure whether this is the best of even correct solution but it gets the job done.