Jon Douglas The rantings of a developer

Being Reactive


One of my goals as a developer has been to learn what the big deal is regarding RX(Reactive Extensions). I’ve always been interested in learning more about it, but I’ve had multiple learning blocks trying to wrap my head around it. I first started learning about RX(Reactive Extensions) back in 2013. It’s been four years since and I’m still struggling to learn it. So I figured what better way to learn it other than writing about it?

Why learn RX(Reactive Extensions) from a developer standpoint?

RX has slowly overtaken various development communities by storm. Here’s a few reasons why I personally dived into RX.

Okay…but Why?

I’m not going to convince you with a pros and cons list, but rather I’m going to give an example of how RX can help you.

Scenario: Family BBQ

Imagine the application we are going to create mimics a family BBQ in which hamburgers are served. Let’s give some roles to our family members based on what they are responsible for preparing.

  • Brother - Responsible for preparing raw meat.
  • Sister - Responsible for heating up buns.
  • Father - Responsible for cooking the meat.
  • Mother - Responsible for cutting fresh vegetables.
  • You - Responsible for putting everything together to make a hamburger.


Brother is taking out raw meat packages from the freezer and following a few steps:

  1. Making sure the meat has not gone bad.
  2. Seasoning the meat.
  3. Rolling the meat into patties.

It takes Brother 3 seconds to prepare each piece of meat.

In short: He is checking that the meat is not Rotten and then preparing each piece in 3 seconds.


Sister is taking buns out of the freezer and following a couple of steps:

  1. Defrosting the buns.
  2. Heating up the buns.

It takes Sister 5 seconds to heat each bun.

In short: She is Heating the buns which takes 5 seconds each.


Father is near the grill ready to cook and following a couple of steps:

  1. Waiting for Brother to prepare the meat.
  2. Cooking each piece of meat as it comes to him.

Father is fast! It doesn’t take him anytime to cook the meat.

In short: He is Cooking the raw meat when brother provides it as soon as possible.


Mother is cutting up lettuce and following a couple of steps:

  1. Making sure the lettuce has not gone bad.
  2. Removing the outer leaves and core from the lettuce head
  3. Chop the lettuce

It takes Mother 2 seconds to prepare the lettuce.

In short: She is preparing the lettuce which takes 2 seconds.


You are waiting for your family to finish all of their tasks so you can do yours.

In short: You will be taking a Cooked Meat, Heated Bun, and Lettuce to create a Hamburger as soon as you get each ingredient.


You may also notice that each one of our family members have a role in which they are producing something. However each stream has a different set of dependencies, filters, transformations, and combinations they must adhere to. Each stream also might take different amounts of time to complete.


This is a way to ensure that we are assembling a perfectly edible hamburger so we do not get sick during our family BBQ.

We only have one example of a filter in this sample:

Brother - Checks to ensure each meat is not Rotten.


We are also transforming our ingredients to different states.

We have two examples of tranformations in this sample:

Father - Puts the raw meat on the grill which makes them Cooked.

Sister - Puts the buns in the microwave which make them Heated.


Now we need to finally create our hamburger based on the other streams our family is producing. I’ve color coordinated each ingredient to show what hamburger it belongs to. The items marked in Red sadly get discarded because we don’t have enough Meat that is Cooked, sadly Brother has already thrown away the Rotten meat.

RX in Action

Why is this better?

This is because reactive programming lets you focus on what you’re trying to achieve rather than on the technical details of making it work. This leads to simple and readable code and eliminates most boilerplate code (such as change tracking or state management) that distracts you from the intent of your code logic. When the code is short and focused, it’s less buggy and easier to grasp.

Quoted from the book RX.NET in Action

The Code

You can find the code which you can run locally in Visual Studio or LINQPad here:

This sample will run continuously to demonstrate assembling a hamburger.

Note: Don’t forget to install RX - Main into your project!


It took me over 4 slow years to realize that Reactive Extensions(RX) is a good idea. It’s never too late to start learning something new. I’m learning something new about RX everyday at a snail’s pace, but at least I’m learning something!

Big thanks to Shane Neuville( and Paul Betts( for various tips and tricks on earlier drafts of this blog post!

Note: The diagrams in this blog post are RTL when in reality most diagrams show LTR such as marble diagrams. This was a bit easier for me to learn with.


Icons were used from the Noun Project .

Bun - Karina M
Hamburger - chiara galli
Romaine Lettuce - Imogen Oh
Microwave - Nook Fulloption
Grill - Aleksandr Vector
Meat - Vladimir Belochkin
Meat -  Rutmer Zijlstra
Flies - Blaise Sewell
Heat -  Stan Diers

Xamarin.Android Book

If you enjoyed this post, please consider subscribing to my upcoming book’s email list:

You can signup at the following link: Programming Xamarin.Android Email List

MSBuild Basics

MSBuild Basics

MSBuild is the music conductor of build tooling. It is extremely powerful for understanding and customizing your build process.

Quick Installation

You should have MSBuild installed already on your computer. Ensure you are in the correct path or add the msbuild path to your Environment Variables.

Basic MSBuild command:

msbuild [INPUT].csproj /t:[TARGET]

Project File (.csproj is the MSBuild file)

<Project xmlns="">

Xamarin.Android Example:

<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="">

All content will be placed inside of the <Project> tag. This includes, properties, items, targets, etc.

Think of this as the files being build, parameters for build, and much more.


MSBuild properties are key-value pairs. The key is the name that you use to refer the property. The value is the value of the property.

When declaring a property, they must be contained inside a <PropertyGroup> element. This element must be inside of the <Project> element.

Note: You can have separate properties as long as they are in their own element.

Xamarin.Android Example:

    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

Tasks and Targets


A Task is the smallest unit of work. Typically known as an action or routine.

Example of a Task:

<Message Text="Hello Support Team Members!" />


A Target is a series of executable steps/tasks.

Example of an empty Target:

<Target Name="HelloSupportTeam">

Default Tasks

Copy, Move, Exec, ResGen, Csc - Copy Files, Move Files, Execute a program, Generate Resources, C# Compiler

Message - Sends a message to the loggers that are listening in the build process.

<Target Name="HelloSupportTeam">
    <Message Text="Hello Support Team Members!" />

Running a Target

A Target can be run in MSBuild simply by the following syntax

msbuild MyProject.csproj /t:<TargetName> or msbuild MyProject.csproj /target:<TargetName>

Let’s try running the HelloSupportTeam target now.

msbuild MyProject.csproj /t:HelloSupportTeam

You should see the following output:

  Hello Support Team Members!

Properties inside a Task

Let’s now define a <PropertyGroup> with our message instead.

    <HelloSupportTeamMessage>Hello again brownbaggers!</HelloSupportTeamMessage>

Now we need to use the property variable instead. Let’s edit our <Message> Task. The syntax for a property in MSBuild is $(PropertyName):

<Target Name="HelloSupportTeam">
    <Message Text="$(HelloSupportTeamMessage)" />

Items (Aka Files)

Items are file-based references. Similar to <PropertyGroup>, you define them by using an <ItemGroup> instead.

Xamarin.Android Example:

    <Compile Include="MainActivity.cs" />
    <Compile Include="Resources\Resource.Designer.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />

To evaulate an item, you would use the @(ItemType) syntax. Let’s now spit out a Message to see what is all going to be compiled here.

<Target Name="PrintCompileInfo">
    <Message Text="Compile: @(Compile)" />

Item Metadata

Items have metadata to them as well. There are many well-known metadata items that we can query, however I will not be going into detail on them all. Here is a sample of getting the directory of an item:

<Target Name="PrintMetadata">
    <Message Text="%40(Compile-> '%25(Directory)'): @(Compile->'%(Directory)')" />

Conditions (

Condition are used to evaluate a true or false condition.

Xamarin.Android Example:

  <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

You can check multiple types of conditions such as:

  • == - Equality
  • != - Inequality
  • Exists - If something exists
  • !Exists - If something does not exist

Conditions are especially useful for adding an Item based on a condition such as a $(Configuration) being Debug or Release

Initial Targets

You may be asking yourself…How the hell do we know what Target get executed first? Well the truth is, I slipped a detail past you really quickly. Let’s go back to our original definition of our <Project>:

<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="">

This will default any Target named Build will be the default target if no other Target is defined when invoking.

Extending MSBuild

Okay now for the actual fun part. Extending the build process.

There’s a few ways to extend the MSBuild process in the sense of a pre or post build action.

  1. Pre and Post build events
  2. Override BeforeBuild / AfterBuild target
  3. Extend the BuildDependsOn list
<Target Name="BeforeBuild">

<Target Name="AfterBuild">

Common files names

.proj or .csproj

.proj is the generic. .csproj is a C# specific. .vbproj is the Visual Basic specific


.targets is a file that contains shared targets which are imported into other files


.props is a file that contains settings for the build process


.tasks is a file that contains UsingTask definitions

Intellisense of items

There’s a few xsd files that are used in VS for general intellisense. You can also look for an item directly by opening the schema:

C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Xml\Schemas\1033\MSBuild

Debugging Tasks

Three main ways:

  1. Use logs of logging statements and examine the logger
  2. Use Debugger.Launch() to prompt for a debugger attachment
  3. Start MSBuild as an external program, and then debug normally

Other Resources

The most invaluable resource you’ll have on MSBuild is Sayed’s book:

Video Resources:

Xamarin.Android Proguard Notes


So you’ve heard of this tool called “Proguard” which can Shrink and Optimize unused code from our apps and the libraries they reference. Little did you know that you actually have to do a bit of work so Proguard can work for you.

Holy Notes Batman!

Have you ever enabled Proguard in your project and now your Build Output is plagued by logs of Note:?

Here’s a sample of a Build Output of a project that has the Xamarin Android Support Library - Design( installed. This of course has a large list of dependencies on other support libraries.

You may notice hundreds of notes saying

Note: the configuration doesn't specify which class members to keep for class `package.ClassName`

Proguard Summary

However let’s first get some numbers about just how much is affecting us. At the bottom of our Proguard Task, we will find a summary that let’s us know exactly how much.

1>  Note: there were 109 references to unknown classes. (TaskId:247)
1>        You should check your configuration for typos. (TaskId:247)
1>        ( (TaskId:247)
1>  Note: there were 1 classes trying to access generic signatures using reflection. (TaskId:247)
1>        You should consider keeping the signature attributes (TaskId:247)
1>        (using '-keepattributes Signature'). (TaskId:247)
1>        ( (TaskId:247)
1>  Note: there were 10 unkept descriptor classes in kept class members. (TaskId:247)
1>        You should consider explicitly keeping the mentioned classes (TaskId:247)
1>        (using '-keep'). (TaskId:247)
1>        ( (TaskId:247)
1>  Note: there were 5 unresolved dynamic references to classes or interfaces. (TaskId:247)
1>        You should check if you need to specify additional program jars. (TaskId:247)
1>        ( (TaskId:247)
1>  Note: there were 6 accesses to class members by means of introspection. (TaskId:247)
1>        You should consider explicitly keeping the mentioned class members (TaskId:247)
1>        (using '-keep' or '-keepclassmembers'). (TaskId:247)
1>        ( (TaskId:247)

Proguard Reminder

Before jumping into these items one by one, let’s first understand what’s going on when we are calling Proguard.

Simply put, we are calling the Proguard.jar and providing various Configuration files that depict how Proguard should process the shrinking.

The three main files to care about are the following:


These are rules unique to Xamarin. Such as ensuring to keep the mono, android, and java classes that Xamarin.Android relies on.



These are rules that are generated based on the ACW(Android Callable Wrappers) of your references. In this case the Xamarin.Android.Support.Design library and it’s dependencies.



These are rules that are generated based on your Application.


Custom proguard.cfg

Finally it will include your custom Proguard.cfg file which is defined with the Build Action of ProguardConfiguration.

Let’s break these notes down one by one:

references to unknown classes

1>  Note: there were 109 references to unknown classes. (TaskId:247)
1>        You should check your configuration for typos. (TaskId:247)
1>        ( (TaskId:247)

Your configuration refers to the name of a class that is not present in the program jars or library jars. You should check whether the name is correct. Notably, you should make sure that you always specify fully-qualified names, not forgetting the package names.

We can now search for the keywords unknown class within our Build Output and see what type of classes it’s throwing this Note: for.

EX: Note: the configuration refers to the unknown class ''

So it is saying that our configuration refers to this unknown class, but if we did a bit of searching, we don’t see this class anywhere within our .cfg files above. Let’s add some diagnostics by adding the -printconfiguration config.txt rule into our custom Proguard.cfg file.

If we now look through this config.txt file, we will see the rule caught red handed:

-keep public class

Unfortunately this is a limitation of generation of Proguard rules. Some of these will be completely out of your control.

access generic signatures using reflection

1>  Note: there were 1 classes trying to access generic signatures using reflection. (TaskId:247)
1>        You should consider keeping the signature attributes (TaskId:247)
1>        (using '-keepattributes Signature'). (TaskId:247)
1>        ( (TaskId:247)

Your code uses reflection to access metadata from the code, with an invocation like “class.getAnnotations()”. You then generally need to preserve optional class file attributes, which ProGuard removes by default. The attributes contain information about annotations, enclosing classes, enclosing methods, etc. In a summary in the log, ProGuard provides a suggested configuration, like -keepattributes Annotation. If you’re sure the attributes are not necessary, you can switch off these notes by specifying the -dontnote option.

This one however is straight forward by just adding the -keepattributes Signature to our Custom Proguard.cfg file.

unkept descriptor classes in kept class members.

1>  Note: there were 10 unkept descriptor classes in kept class members. (TaskId:247)
1>        You should consider explicitly keeping the mentioned classes (TaskId:247)
1>        (using '-keep'). (TaskId:247)
1>        ( (TaskId:247)

Your configuration contains a -keep option to preserve the given method (or field), but no -keep option for the given class that is an argument type or return type in the method’s descriptor. You may then want to keep the class too. Otherwise, ProGuard will obfuscate its name, thus changing the method’s signature. The method might then become unfindable as an entry point, e.g. if it is part of a public API. You can automatically keep such descriptor classes with the -keep option modifier includedescriptorclasses (-keep,includedescriptorclasses …). You can switch off these notes by specifying the -dontnote option.

You know the process now, let’s search for “descriptor class” in our Build Output.

EX: Note: the configuration keeps the entry point '$SnackbarBaseLayout { void setOnLayoutChangeListener($OnLayoutChangeListener); }', but not the descriptor class '$OnLayoutChangeListener'

Again, search the config.txt for the first class to ensure it’s there:

i.e. -keep class$SnackbarBaseLayout

We do see it inside. So it’s saying we need a -keep rule for$OnLayoutChangeListener. Let’s now add that to our Custom Proguard.cfg file:

-keep class$OnLayoutChangeListener

unresolved dynamic references to classes or interfaces.

1>  Note: there were 5 unresolved dynamic references to classes or interfaces. (TaskId:247)
1>        You should check if you need to specify additional program jars. (TaskId:247)
1>        ( (TaskId:247)

ProGuard can’t find a class or interface that your code is accessing by means of introspection. You should consider adding the jar that contains this class.

Let’s search for dynamically referenced class in our Build Output.

EX: Note: can't find dynamically referenced class

Unfortunately this one isn’t that straight forward as something is referencing classes or interfaces that are not present in our project. To solve this, we would have to find the dependency and add it via NuGet.

accesses to class members by means of introspection.

1>  Note: there were 6 accesses to class members by means of introspection. (TaskId:247)
1>        You should consider explicitly keeping the mentioned class members (TaskId:247)
1>        (using '-keep' or '-keepclassmembers'). (TaskId:247)
1>        ( (TaskId:247)

Your code uses reflection to find a fields or a method, with a construct like “.getField(“myField”)”. Depending on your application, you may need to figure out where the mentioned class members are defined and keep them with an option like “-keep class MyClass { MyFieldType myField; }”. Otherwise, ProGuard might remove or obfuscate the class members, since it can’t know which ones they are exactly. It does list possible candidates, for your information. You can switch off these notes by specifying the -dontnote option.

EX: Note: accesses a declared field 'icon' dynamically

We may just want to let Proguard know “Hey please don’t note me on this”. We can use the -dontnote rule for this specific class. Let’s add this to our Custom Proguard.cfg file:



Now you should know the basics of how Proguard shrinks our code and how we can adjust to the notes that proguard gives us. For the most part, Proguard does a great job of documenting what is going on and how you can fix certain scenarios. Take the time to read through your Proguard logs to optimize the ruleset so Proguard can work for you!

As a bonus, you can always start off with some of these community created Proguard rules to help give you a jump start with these libraries and proguard.

If you enjoyed this post, please consider subscribing to my upcoming book’s email list:

You can signup at the following link: Programming Xamarin.Android Email List

Xamarin.Android Linker Tricks Part 1 - Bitdiffer


The linker used in Xamarin.Android applications has historically been a painpoint for developers.

This is mainly because as developers, we only use a small portion of the assemblies we consume. For the rest of those assemblies, we consider using a linker mechanism so we reap the benefits of having a smaller assembly at the end of the day.

To give a real world example of what the linker does, I’ve created three .apk files with the different linker options:

  • None
  • Sdk Assemblies Only
  • Sdk and User Assemblies
04/13/2017  11:15 AM        52,160,463 LinkerSample.None.apk
04/13/2017  11:12 AM        21,995,031 LinkerSample.SDK.apk
04/13/2017  11:16 AM        10,130,214 LinkerSample.UserAndSDK.apk

Note: This project includes a reference to the Xamarin.Android.Support.Design NuGet to demonstrate something more than “Hello World”

As you can see, we see the size of 52mb(None), 21mb(SDK), and 10mb(User and SDK). What this means is that in a perfect world, we would want to use Sdk and User Assemblies so we can keep our .apk size down. However using that setting is considered the most aggressive linker setting and it can strip away things that you need to use in your application. Finding out exactly what it strips out is a bit difficult and we should fallback to other tooling.

Using bitdiffer

bitdiffer is a tool that helps compare assembly files. It is extremely useful in the sense of a practical GUI/CLI that lets us see the difference between assemblies. You can download it here:

One of the most useful things bitdiffer does is allows you to add not only 2 assemblies, but a full list for comparison. This is extremely useful for us as developers to see what exactly each linker option does to our assembly.

Consider the following example with the three .apk we created earlier comparing against the Mono.Android.dll assembly. They are ordered None, Sdk Assemblies Only, Sdk and User Assemblies in the tabs:

You can notice off a quick glance that we had quite a difference in Members Changed or Removed between the linker setting None -> Sdk Assemblies Only -> Sdk and User Assemblies.

Now that’s not the only cool feature of this tool, you can also dive down into a specific class to see the diff between your assemblies:

And finally we can dig into what the difference is between members in our class:

Although this is only part 1 of various linker tricks I use to diagnose a problem, this is one of the more powerful ways to approach any linker issues in your project to understand the problem.

If you enjoyed this post, please consider subscribing to my upcoming book’s email list:

You can signup at the following link: Programming Xamarin.Android Email List

APK Tools

APK Tools

I’ve found many APK tools to be quite useful for diagnosing issues with Xamarin.Android. Here is a small list of tools that I find helpful.


apktool is a tool for reverse engineering Android applications. It can be used to decode resources to nearly original form and rebuild them after making some modifications.


One of the most useful usecases of apktool is to ensure your generated .apk is correct. You can use the decode / d method to take an .apk and “unzip” it’s original contents.

usage: apktool d MyApplication.apk


The other usecase is to build a .apk after making a couple of modifications. You can use the build / b method to build an .apk

usage: apktool b foo

Which will build a folder named foo into an .apk file.

Note: If you aren’t using the wrapper script, you may need to invoke it via java -jar apktool.jar


aapt provides a couple of useful tools for our .apk files. You can find aapt inside of your Android SDK’s build-tools folder.


aapt list - shows the contents of the package.

usage: aapt list MyApplication.apk



aapt dump - provides values of individual elements or parts of a package. There are a few different items we can dump:

badging - dumps badging information like the versions, sdk targets, etc

usage: aapt dump badging MyApplication.apk

package: name='MyApplication.MyApplication' versionCode='1' versionName='1.0' platformBuildVersionName='7.1.1'
application: label='' icon='res/drawable/icon.png'
launchable-activity: name='md5ef8aabbe49b48f4362a43abcfb4dce14.MainActivity'  label='MyApplication' icon='res/drawable/icon.png'
feature-group: label=''
  uses-feature: name='android.hardware.faketouch'
  uses-implied-feature: name='android.hardware.faketouch' reason='default feature for all apps'
supports-screens: 'small' 'normal' 'large' 'xlarge'
supports-any-density: 'true'
densities: '160'
native-code: 'armeabi-v7a'

permissions - dumps permission information such as what uses-permissions are in use

usage: aapt dump permissions MyApplication.apk

package: MyApplication.MyApplication
uses-permission: name='android.permission.INTERNET'
uses-permission: name='android.permission.READ_CALENDAR'
uses-permission: name='android.permission.READ_CONTACTS'

resources - dumps resources in each resource category such as string/array/layout/etc

usage: aapt dump resources MyApplication.apk

Package Groups (1)
Package Group 0 id=0x7f packageCount=1 name=MyApplication.MyApplication
  Package 0 id=0x7f name=MyApplication.MyApplication
    type 1 configCount=1 entryCount=1
      spec resource 0x7f020000 MyApplication.MyApplication:drawable/icon: flags=0x00000000
      config (default):
        resource 0x7f020000 MyApplication.MyApplication:drawable/icon: t=0x03 d=0x00000000 (s=0x0008 r=0x00)
    type 2 configCount=1 entryCount=1
      spec resource 0x7f030000 MyApplication.MyApplication:layout/main: flags=0x00000000
      config (default):
        resource 0x7f030000 MyApplication.MyApplication:layout/main: t=0x03 d=0x00000001 (s=0x0008 r=0x00)
    type 3 configCount=1 entryCount=2
      spec resource 0x7f040000 MyApplication.MyApplication:string/Hello: flags=0x00000000
      spec resource 0x7f040001 MyApplication.MyApplication:string/ApplicationName: flags=0x00000000
      config (default):
        resource 0x7f040000 MyApplication.MyApplication:string/Hello: t=0x03 d=0x00000002 (s=0x0008 r=0x00)
        resource 0x7f040001 MyApplication.MyApplication:string/ApplicationName: t=0x03 d=0x00000003 (s=0x0008 r=0x00)

configurations - dumps any configuration that has been setup

usage: aapt dump configurations MyApplication.apk

imsi=0/0 lang=-- reg=-- orient=0 touch=0 dens=160 kbd=0 nav=0 input=0 scrnW=0 scrnH=0 sz=0 long=0 vers=0.0
imsi=0/0 lang=-- reg=-- orient=0 touch=0 dens=240 kbd=0 nav=0 input=0 scrnW=0 scrnH=0 sz=0 long=0 vers=0.0
imsi=0/0 lang=-- reg=-- orient=0 touch=0 dens=0 kbd=0 nav=0 input=0 scrnW=0 scrnH=0 sz=0 long=0 vers=0.0

xmltree - dumps the xml parse tree for an xml file in a package

usage: aapt dump xmltree MyApplication.apk res/layout/main.xml

N: android=
  E: LinearLayout (line=1)
    A: android:orientation(0x010100c4)=(type 0x10)0x1
    A: android:layout_width(0x010100f4)=(type 0x10)0xffffffff
    A: android:layout_height(0x010100f5)=(type 0x10)0xffffffff

xmlstrings - dumps all strings inside for an xml file in a package

usage: aapt dump xmlstrings MyApplication.apk res/layout/main.xml

String pool of 7 unique UTF-8 non-sorted strings, 7 entries and 0 styles using 176 bytes:
String #0: orientation
String #1: layout_width
String #2: layout_height
String #3: android
String #4:
String #5:
String #6: LinearLayout


ClassyShark is a binary inspection tool that can help you find information such as your total dex count, decompilation of .class files, and much more. It supports .dex, .aar, .so, .apk, .jar, .class, .xml files for further inspection.

usage: java -jar classyshark.jar

You should see a program like the following:

You can then inspect any aspect of your binary such as decompiling a class, viewing what’s inside of a dex file, and much more.


You can view what’s inside of your main dex list. Also known as the classes.dex file that is generated in the Android build process.

Methods Count

You can also see the current method count of the classes.dex list from an overview


Although this blog post only showcases 3 tools, there are so many ways to get information from your binaries to diagnose issues such as multidex, versioning, etc in you Xamarin.Android application!

If you enjoyed this post, please consider subscribing to my upcoming book’s email list:

You can signup at the following link: Programming Xamarin.Android Email List