Document - Tutorial Xamarin
Document - Tutorial Xamarin
Xamarin.Android
Getting Started
Setup and Installation
Windows Installation
Android SDK Setup
Android Emulator Setup
Hardware Acceleration
Device Manager
Device Properties
Troubleshooting
Android Device Setup
Microsoft OpenJDK Preview
Hello, Android
Part 1: Quickstart
Part 2: Deep Dive
Hello, Android Multiscreen
Part 1: Quickstart
Part 2: Deep Dive
Xamarin for Java Developers
Application Fundamentals
Accessibility
Android API Levels
Android Resources
Android Resource Basics
Default Resources
Alternate Resources
Creating Resources for Varying Screens
Application Localization and String Resources
Using Android Assets
Fonts
Activity Lifecycle
Walkthrough - Saving the Activity state
Android Services
Creating a Service
Bound Services
Intent Services
Started Services
Foreground Services
Out of Process Services
Service Notifications
Broadcast Receivers
Localization
Permissions
Graphics and Animation
CPU Architectures
Handling Rotation
Audio
Notifications
Local Notifications
Local Notifications Walkthrough
Touch
Touch in Android
Walkthrough – Using Touch in Android
Multi-Touch Tracking
HttpClient Stack and SSL/TLS
Writing Responsive Apps
User Interface
Android Designer
Using the Android Designer
Designer Basics
Resource Qualifiers and Visualization Options
Alternative Layout Views
Material Design Features
Material Theme
User Profile
Splash Screen
Layouts
LinearLayout
RelativeLayout
TableLayout
RecyclerView
Parts and Functionality
RecyclerView Example
Extending the Example
ListView
ListView Parts and Functionality
Populating a ListView With Data
Customizing a ListView's Appearance
Using CursorAdapters
Using a ContentProvider
ListView and the Activity Lifecycle
GridView
GridLayout
Tabbed Layouts
Navigation Tabs with the ActionBar
Controls
ActionBar
Auto Complete
Buttons
Radio Button
Toggle Button
CheckBox
Custom Button
Calendar
CardView
EditText
Gallery
Navigation Bar
Pickers
Date Picker
Time Picker
Popup Menu
Spinner
Switch
TextureView
Toolbar
Replacing the Action Bar
Adding a Second Toolbar
Toolbar Compatibility
ViewPager
ViewPager with Views
ViewPager with Fragments
WebView
Platform Features
Android Beam
Android Manifest
File Access with Xamarin.Android
External Storage
Fingerprint Authentication
Getting Started
Scanning for Fingerprints
Creating the CryptoObject
Responding to Authentication Callbacks
Guidance & Summary
Enrolling a Fingerprint
Android Job Scheduler
Firebase Job Dispatcher
Fragments
Implementing Fragments
Fragments Walkthrough - Part 1
Fragments Walkthrough - Part 2
Creating a Fragment
Managing Fragments
Specialized Fragment Classes
Providing Backwards Compatibility
App Linking
Android 8 Oreo
Android 7 Nougat
Android 6 Marshmallow
Android 5 Lollipop
Android 4.4 KitKat
Android 4.1 Jelly Bean
Android 4.0 Ice Cream Sandwich
Content Providers
How it Works
Using the Contacts ContentProvider
Creating a Custom ContentProvider
Maps and Location
Location
Maps
Maps Application
Maps API
Obtaining a Google Maps API Key
Using Android.Speech
Java Integration
Android Callable Wrappers
Working With JNI
Porting Java to C#
Binding a Java Library
Binding a .JAR
Binding an .AAR
Binding an Eclipse Library Project
Customizing Bindings
Java Bindings Metadata
Naming Parameters with Javadoc
Troubleshooting Bindings
Using Native Libraries
Renderscript
Xamarin.Essentials
Getting Started
Accelerometer
App Information
Battery
Clipboard
Compass
Connectivity
Data Transfer
Device Display Information
Device Information
Email
File System Helpers
Flashlight
Geocoding
Geolocation
Gyroscope
Magnetometer
Main Thread
Open Browser
Orientation Sensor
Phone Dialer
Power
Preferences
Screen Lock
Secure Storage
SMS
Text-to-Speech
Version Tracking
Vibrate
Troubleshooting
Data and Cloud Services
Azure Active Directory
Getting Started
Step 1. Register
Step 2. Configure
Accessing the Graph API
Azure Mobile Apps
Data Access
Introduction
Configuration
Using SQLite.NET ORM
Using ADO.NET
Using Data in an App
Google Messaging
Firebase Cloud Messaging
FCM Notifications Walkthrough
Google Cloud Messaging
GCM Notifications Walkthrough
Web Services
Walkthrough - Working with WCF
Deployment and Testing
App Package Size
Building Apps
Build Process
Building ABI-Specific APKs
Command Line Emulator
Debugging
Debug on the Emulator
Debug on a Device
Android Debug Log
Debuggable Attribute
Environment
GDB
Custom Linker Settings
Multi-core devices
Performance
Profiling
Preparing for Release
ProGuard
Signing the APK
Manually Signing the APK
Finding Your Keystore Signature
Publishing an App
Publishing to Google Play
Google Licensing Services
APK Expansion Files
Manually Uploading the APK
Publishing to Amazon
Publishing Independently
Install as System App
Advanced Concepts and Internals
Architecture
Available Assemblies
API Design
Garbage Collection
Limitations
Troubleshooting
Troubleshooting Tips
Frequently Asked Questions
Which Android SDK packages should I install?
Where can I set my Android SDK locations?
How do I update the Java Development Kit (JDK) version?
Can I use Java Development Kit (JDK) version 9?
How can I manually install the Android Support libraries required by the
Xamarin.Android.Support packages?
How do I install Google Play Services in an emulator?
What USB drivers do I need to debug Android on Windows?
Is it possible to connect to Android emulators running on a Mac from a Windows
VM?
How do I automate an Android NUnit Test project?
How do I enable Intellisense in Android .axml files?
Why can't my Android release build connect to the Internet?
Smarter Xamarin Android Support v4 / v13 NuGet Packages
How do I resolve a PathTooLongException?
What version of Xamarin.Android added Lollipop support?
Android.Support.v7.AppCompat - No resource found that matches the given
name: attr 'android:actionModeShareDrawable'
Adjusting Java memory parameters for the Android designer
My Android Resource.designer.cs file will not update
Resolving Library Installation Errors
Changes to the Android SDK Tooling
Xamarin.Android Errors Reference
Wear
Getting Started
Introduction to Android Wear
Setup & Installation
Hello, Wear
User Interface
Controls
GridViewPager
Platform Features
Creating a Watch Face
Screen Sizes
Deployment & Testing
Debug on an Emulator
Debug on a Wear Device
Packaging
Release Notes
Samples
Getting Started Series
5/2/2018 • 2 minutes to read • Edit Online
Hello, Android
In this two-part guide, you'll build your first Xamarin.Android application using Visual Studio, and you'll develop an
understanding of the fundamentals of Android application development with Xamarin. Along the way, this guide
introduces you to the tools, concepts, and steps required to build and deploy a Xamarin.Android application.
The topics in this section explain how to install and configure Xamarin.Android to work with Visual Studio on
Windows and macOS, how to use the Android SDK Manager to download and install Android SDK tools and
components that are required for building and testing your app, how to configure the Android emulator for
debugging, and how to connect a physical Android device to your development computer for debugging and final
testing your app.
Windows Installation
This guide walks you through the installation steps and configuration details required to install Xamarin.Android
on Windows. By the end of this article, you will have a working Xamarin.Android installation integrated into Visual
Studio, and you'll be ready to start building your first Xamarin.Android application.
Mac Installation
This article walks you through the installation steps and configuration details required to install Xamarin.Android
on a Mac. By the end of this article, you will have a working Xamarin.Android installation integrated into Visual
Studio for Mac, and you'll be ready to start building your first Xamarin.Android application.
This guide describes the steps for installing Xamarin.Android for Visual Studio on Windows, and it explains how to
configure Xamarin.Android for building your first Xamarin.Android application.
Overview
Because Xamarin is now included with all editions of Visual Studio at no extra cost and does not require a separate
license, you can use the Visual Studio installer to download and install Xamarin.Android tools. (The manual
installation and licensing steps that were required for earlier versions of Xamarin.Android are no longer necessary.)
In this guide, you will learn the following:
How to configure custom locations for the Java Development Kit, Android SDK, and Android NDK.
How to launch the Android SDK Manager to download and install additional Android SDK components.
How to prepare an Android device or emulator for debugging and testing.
How to create your first Xamarin.Android app project.
By the end of this guide, you will have a working Xamarin.Android installation integrated into Visual Studio, and
you will be ready to start building your first Xamarin.Android application.
Installation
For detailed information on installing Xamarin for use with Visual Studio on Windows, see the Windows Install
guide.
Configuration
Xamarin.Android uses the Java Development Kit (JDK) and the Android SDK to build apps. During installation, the
Visual Studio installer places these tools in their default locations and configures the development environment
with the appropriate path configuration. You can view and change these locations by clicking Tools > Options >
Xamarin > Android Settings:
For most users these default locations will work without further changes. However, you may wish to configure
Visual Studio with custom locations for these tools (for example, if you have installed the Java JDK, Android SDK,
or NDK in a different location). Click Change next to a path that you want to change, then navigate to the new
location.
Xamarin.Android uses JDK 8, which is required if you are developing for API level 24 or greater (JDK 8 also
supports API levels earlier than 24). You can continue to use JDK 7 if you are developing specifically for API level
23 or earlier.
IMPORTANT
Xamarin.Android does not support JDK 9.
You can use the Google Android SDK Manager to install versions of the Android SDK Tools package up to version
25.2.3. However, if you need to use a later version of the Android SDK Tools package, you must install the Xamarin
Android SDK Manager plugin for Visual Studio (available from the Visual Studio Marketplace). This is necessary
because Google's standalone SDK Manager was deprecated in version 25.2.3 of the Android SDK Tools package.
For more information about using the Xamarin Android SDK Manager, see Android SDK Setup.
Android Emulator
The Android Emulator can be helpful tool to develop and test a Xamarin.Android app. For example, a physical
device such as a tablet may not be readily available during development, or a developer may want to run some
integration tests on their computer before committing code.
Emulating an Android device on a computer involves the following components:
Google Android Emulator – This is an emulator based on QEMU that creates a virtualized device running on
the developer's workstation.
An Emulator Image – An emulator image is a template or a specification of the hardware and operating
system that is meant to be virtualized. For example, one emulator image would identify the hardware
requirements for a Nexus 5X running Android 7.0 with Google Play Services installed. Another emulator image
might specific a 10" table running Android 6.0.
Android Virtual Device (AVD ) – An Android Virtual Device is an emulated Android device created from an
emulator image. When running and testing Android apps, Xamarin.Android will start the Android Emulator,
starting a specific AVD, install the APK, and then run the app.
A significant improvement in performance when developing on x86 based computers can be achieved by using
special emulator images that are optimized for x86 architecture and one of two virtualization technologies:
1. Microsoft's Hyper-V – Available on computers running the Windows 10 April Update.
2. Intel's Hardware Accelerated Execution Manager (HAXM ) – Available on x86 computers running OS X, macOS,
or older version of Windows.
For more information about the Android Emulator, Hyper-V, and HAXM, please see Hardware Acceleration for
Emulator Performance guide.
NOTE
On older versions of Windows, HAXM is not compatible with Hyper-V. In this scenario it is necessary to either disable Hyper-
V or to use the slower emulator images that do not have the x86 optimizations.
Android Device
If you have a physical Android device to use for testing, this is a good time to set it up for development use. See
Set Up Device for Development to configure your Android device for development, then connect it to your
computer for running and debugging Xamarin.Android applications.
Create an Application
Now that you have installed Xamarin.Android, you can launch Visual Studio create a new project. Click File > New
> Project to begin creating your app:
In the New Project dialog, select Android under Templates and click Android App in the right pane. Enter a
name for your app (in the screenshot below, the app is called MyApp), then click OK:
That's it! Now you are ready to use Xamarin.Android to create Android applications!
Summary
In this article, you learned how to set up and install the Xamarin.Android platform on Windows, how to (optionally)
configure Visual Studio with custom Java JDK and Android SDK installation locations, how to launch the SDK
Manager to install additional Android SDK components, how to setup an Android device or emulator, and how to
start building your first application.
The next step is to have a look at the Hello, Android tutorials to learn how to create a working Xamarin.Android
app.
Related Links
Download Visual Studio
Installing Visual Studio Tools for Xamarin
System Requirements
Android SDK Setup
Android Emulator Setup
Set Up Device For Development
Run Apps on the Android Emulator
Setting up the Android SDK for Xamarin.Android
7/10/2018 • 8 minutes to read • Edit Online
Visual Studio includes an Android SDK Manager that you use to download Android SDK tools, platforms, and
other components that you need for developing Xamarin.Android apps.
Overview
This guide explains how to use the Xamarin Android SDK Manager in Visual Studio and Visual Studio for Mac.
NOTE
This guide applies only to Visual Studio 2017 and Visual Studio for Mac.
The Xamarin Android SDK Manager (installed as part of the Mobile development with .NET workload) helps
you download the latest Android components that you need for developing your Xamarin.Android app. It
replaces Google's standalone SDK Manager, which has been deprecated.
Visual Studio
Visual Studio for Mac
Requirements
To use the Xamarin Android SDK Manager, you will need the following:
Visual Studio 2017 (Community, Professional, or Enterprise edition). Visual Studio 2017 version 15.7 or
later is required.
Visual Studio Tools for Xamarin version 4.10.0 or later.
The Xamarin Android SDK Manager is not compatible with Visual Studio 2015. Users of Visual Studio 2015
should use the SDK Manager tools provided by Google in the Android SDK.
The Xamarin Android SDK Manager also requires the Java Development Kit (which is automatically installed
with Xamarin.Android). Xamarin.Android uses JDK 8, which is required if you are developing for API level 24 or
greater (JDK 8 also supports API levels earlier than 24). You can continue to use JDK 7 if you are developing
specifically for API level 23 or earlier.
IMPORTANT
Xamarin.Android does not support JDK 9.
SDK Manager
To start the SDK Manager in Visual Studio, click Tools > Android > Android SDK Manager:
The Xamarin Android SDK Manager opens in the Android SDKs and Tools screen. This screen has two tabs
– Platforms and Tools:
The Android SDKs and Tools screen is described in more detail in the following sections.
Android SDK Location
The Android SDK location is configured at the top of the Android SDKs and Tools screen, as seen in the
previous image. This location must be configured correctly before the Platforms and Tools tabs will function
properly. You may need to set the location of the Android SDK for one or more of the following reasons:
1. The Xamarin SDK Manager was unable to locate the Android SDK.
2. You have installed the Android SDK in a alternate (non-default) location.
To set the location of the Android SDK, click the … button to the far right of Android SDK Location. This opens
the Browse For Folder dialog to use for navigating to the location of the Android SDK. In the following
screenshot, the Android SDK under Program Files (x86)\Android is being selected:
When you click OK, the Xamarin Android SDK Manager will manage the Android SDK that is installed at the
selected location.
Tools Tab
The Tools tab displays a list of tools and extras. Use this tab to install the Android SDK tools, platform tools, and
build tools. Also, you can install the Android Emulator, the low -level debugger (LLDB ), the NDK, HAXM
acceleration, and Google Play libraries.
For example, to download the Google Android Emulator package, click the check mark next to Android
Emulator and click the Apply Changes button:
A dialog may be shown with the message, Some components can be updated. Do you want to update them
now? Click Yes. Next, a License acceptance dialog is shown:
Click Accept if you accept the Terms and Conditions. At the bottom of the window, a progress bar indicates
download and installation progress. After the installation completes, the Tools tab will show that the selected
tools and extras were installed.
Platforms Tab
The Platforms tab displays a list of platform SDK versions along with other resources (like system images) for
each platform.
This screen lists the Android version (such as Android 7.0), the code name (Nougat), the API level (such as 24),
and the status (Installed if the platform is installed). You use the Platforms tab to install components for the
Android API level that you want to target (for more information about Android versions and API levels, see
Understanding Android API Levels).
If all components of a platform are installed, a checkmark appears next to the platform name. If not all
components of a platform are installed, the box for that platform is filled.
You can expand a platform to see its components (and which components are installed) by clicking the + box to
the left of the platform. Click - to unexpand the component listing for a platform.
To add another platform to the SDK, click the box next to the platform until the checkmark appears to install all of
its components, then click Apply Changes:
To install only the SDK click the box next to the platform once. You can then select any individual components
that you need:
Notice that the number of components to install appears next to the Apply Changes button. In the above
example, six components are ready to install. After you click the Apply Changes button, you will see the License
Acceptance screen:
Click Accept if you accept the Terms and Conditions. You may see this dialog more than one time when there are
multiple components to install. At the bottom of the window, a progress bar will indicate download and
installation progress. When the download and installation process completes (this can take many minutes,
depending on how many components need to be downloaded), the added components are marked with a
checkmark and listed as Installed.
Summary
This guide explained how to install and use the Xamarin Android SDK Manager tool in Visual Studio and Visual
Studio for Mac.
Related Links
Changes to the Android SDK Tooling
Understanding Android API levels
sdkmanager
avdmanager
Android Emulator Setup
6/25/2018 • 2 minutes to read • Edit Online
This guide explain how to prepare the Android Emulator for testing your app.
Overview
The Android Emulator can be run in a variety of configurations to simulate different devices. Each configuration is
called a virtual device. When you deploy and test your app on the emulator, you select a pre-configured or custom
virtual device that simulates a physical Android device such as a Nexus or Pixel phone.
The sections listed below describe how to accelerate the Android emulator for maximum performance, how to use
the Android Device Manager to create and customize virtual devices, and how to customize the profile properties
of a virtual device. In addition, a troubleshooting section explains common emulator problems and workarounds.
Sections
Hardware Acceleration for Emulator Performance
How to prepare your computer for maximum Android Emulator performance. Because the Android Emulator can
be prohibitively slow without hardware acceleration, we recommend that you enable hardware acceleration on
your computer before you use the emulator.
Managing Virtual Devices with the Android Device Manager
How to use the Android Device Manager to create and customize virtual devices.
Editing Android Virtual Device Properties
How to use the Android Device Manager to edit the profile properties of a virtual device.
Android Emulator Troubleshooting
In this article, the most common warning messages and issues that occur while running the Android Emulator are
described, along with workarounds and tips.
After you have configured the Android Emulator, see Debugging on the Android Emulator for information about
how to launch the emulator and use it for testing and debugging your app.
NOTE
As of Android SDK Tools version 26.0.1 and later, Google has removed support for existing AVD/SDK managers in favor of
their new CLI (Command Line Interface) tools. Because of this deprecation change, Xamarin SDK/Device Managers are now
used instead of Google SDK/Device Managers for Android Tools 26.0.1 and later. For more information about the Xamarin
SDK Manager, see Setting up the Android SDK for Xamarin.Android.
Hardware Acceleration for Emulator Performance
6/27/2018 • 6 minutes to read • Edit Online
This article explains how to use your computer's hardware acceleration features to maximize Android Emulator
performance.
Overview
Visual Studio makes it easier for developers to test and debug their Xamarin.Android applications by using the
Android Emulator in situations where an Android device is unavailable or impractical. However, the Android
emulator runs too slowly if hardware acceleration is not available on the computer that runs it. You can drastically
improve the performance of the Android emulator by using special virtual device images that target x86 hardware
in conjunction with one of two virtualization technologies:
1. Microsoft's Hyper-V and the Hypervisor Platform. Hyper-V is a virtualization feature of Windows that
makes it possible to run virtualized computer systems on a physical host computer. This is the
recommended virtualization technology to use for accelerating the Android Emulator. To learn more about
Hyper-V, see Hyper-V on Windows 10.
2. Intel's Hardware Accelerated Execution Manager (HAXM ). HAXM is a virtualization engine for
computers running Intel CPUs. This is the recommended virtualization engine for computers that are
unable to run Hyper-V.
The Android Emulator will automatically make use of hardware acceleration if the following criteria are met:
Hardware acceleration is available and enabled on the development computer.
The emulator is running an emulator image specifically created for an x86-based virtual device.
For information about launching and debugging with the Android Emulator, see Debugging on the Android
Emulator.
Hyper-V
Visual Studio
Visual Studio for Mac
NOTE
Hyper-V support is currently in Preview.
Developers who are using Windows 10 (April 2018 Update or later) are strongly encouraged to use Microsoft's
Hyper-V to accelerate the Android Emulator. To use the Android Emulator with Hyper-V:
1. Update to Windows 10 April 2018 Update (build 1803) or later. To verify which version of Windows is
running, click in the Cortana search bar and type About. Select About your PC in the search results. Scroll
down in the About dialog to the Windows specifications section. The Version should be at least 1803:
2. Enable the Windows Hypervisor Platform. In the Cortana Search bar, type Turn Windows features
on or off. Scroll down in the Windows Features dialog and ensure that Windows Hypervisor Platform
is enabled:
Enabling Windows Hypervisor Platform automatically enables Hyper-V. It is a good idea to restart
Windows after making this change.
3. Install Visual Studio 15.8 Preview 1 or later. This version of Visual Studio provides IDE support for
running the Android Emulator with Hyper-V.
4. Install the Android Emulator package 27.2.7 or later. To install this package, navigate to Tools >
Android > Android SDK Manager in Visual Studio. Select the Tools tab and ensure that the Android
Emulator version is at least 27.2.7. Also ensure that the Android SDK Tools version is 26.1.1 or later:
5. If the emulator version is at least 27.2.7 but less than 27.3.1, the following workaround is required to use
Hyper-V:
a. In the C:\Users\username\.android folder, create a file called advancedFeatures.ini (if it doesn't
already exist).
b. Add the following line to advancedFeatures.ini:
WindowsHypervisorPlatform = on
Known Issues
If you are unable to update to emulator version 27.2.7 or later after updating to a Visual Studio preview,
you may have to directly install the preview installer to enable newer emulator versions.
Performance may be reduced when using certain Intel and AMD -based processors.
Android application may take an abnormal amount of time to load on deployment.
MMIO access error may intermittently prevent a boot of the Android emulator. Restarting the emulator
should resolve this.
HAXM
HAXM is a hardware-assisted virtualization engine (hypervisor) that uses Intel Virtualization Technology (VT) to
speed up Android app emulation on a host machine. Using HAXM in conjunction with Android x86 emulator
images provided by Intel allows for faster Android emulation on VT-enabled systems.
If you are developing on a machine with an Intel CPU that has VT capabilities, you can take advantage of HAXM
to greatly speed up the Android Emulator (if you're not sure whether your CPU supports VT, see Does My
Processor Supports Intel Virtualization Technology?).
NOTE
You can't run a VM-accelerated emulator inside another VM, such as a VM hosted by VirtualBox, VMWare, or Docker. You
must run the Android emulator directly on your system hardware.
Before using the Android Emulator for the first time, it's a good idea to verify that HAXM is installed and available
for the Android Emulator to use.
Verifying HAXM Installation
You can check to see if HAXM is available by viewing the Starting Android Emulator window while the
emulator starts. To start the Android Emulator, do the following:
Visual Studio
Visual Studio for Mac
1. Launch the Android Device Manager by clicking Tools > Android > Android Device Manager:
2. If you see a Performance Warning dialog similar to the following, then HAXM is not yet installed or
configured properly on your computer:
If a Performance Warning dialog like this is shown, see Performance Warnings to identify the cause and
resolve the underlying problem.
3. Select an x86 image (for example, VisualStudio_android-23_x86_phone) and click Start:
4. Watch for the Starting Android Emulator dialog window while the emulator starts up. If HAXM is
installed, you will see the message, HAX is working and emulator runs in fast virt mode as shown in
this screenshot:
If you do not see this message, then HAXM is probably not installed. For example, here is a screenshot of a
message you may see if HAXM is not available:
If HAXM is not available on your computer, use the steps in the next section to install HAXM.
Installing HAXM
If the emulator does not start, HAXM may have to be installed manually. HAXM install packages for both
Windows and macOS are available from the Intel Hardware Accelerated Execution Manager page. Use the
following steps to download and install HAXM manually:
Visual Studio
Visual Studio for Mac
1. From the Intel website, download the latest HAXM virtualization engine installer for Windows. The
advantage of downloading the HAXM installer directly from the Intel website is that you can be assured of
using the latest version.
Alternately, you can use the SDK Manager to download the HAXM installer (In the SDK Manager, click
Tools > Extras > Intel x86 Emulator Accelerator (HAXM installer)). The Android SDK normally
downloads the HAXM installer to the following location:
C:\Program Files (x86)\Android\android-
sdk\extras\intel\Hardware_Accelerated_Execution_Manager
Note that the SDK Manager does not install HAXM, it merely downloads the HAXM installer to the above
location; you still have to launch it manually.
2. Run intelhaxm -android.exe to start the HAXM installer. Accept the default values in the installer dialogs:
Hardware Acceleration and AMD CPUs
Because the Android emulator currently supports AMD hardware acceleration only on Linux, hardware
acceleration is not available for AMD -based computers running Windows.
Related Links
Run Apps on the Android Emulator
Managing Virtual Devices with the Android Device
Manager
6/25/2018 • 12 minutes to read • Edit Online
This article explains how to use the Android Device Manager to create and configure Android Virtual Devices
(AVDs) that emulate physical Android devices. You can use these virtual devices to run and test your app without
having to rely on a physical device.
Overview
After you have verified that hardware acceleration is enabled (as described in Hardware Acceleration for Emulator
Performance), the next step is to use the Android Device Manager (also referred to as the Xamarin Android
Device Manager) to create virtual devices that you can use to test and debug your app.
Visual Studio
Visual Studio for Mac
This article explains how to use the Android Device Manager to create, duplicate, customize, and launch Android
virtual devices.
You use the Android Device Manager to create and configure Android Virtual Devices (AVDs) that run in the
Android Emulator. Each AVD is an emulator configuration that simulates a physical Android device. This makes it
possible to run and test your app in a variety of configurations that simulate different physical Android devices.
Requirements
To use the Android Device Manager, you will need the following:
Visual Studio 2017 version 15.7 or later is required. Visual Studio Community, Professional, and Enterprise
editions are supported.
Visual Studio Tools for Xamarin version 4.9 or later.
The Android SDK must be installed (see Setting up the Android SDK for Xamarin.Android), and SDK tools
version 26.1.1 or later must be installed as explained in the next section. Be sure to install the Android SDK
at the following location (if it is not already installed): C:\Program Files (x86)\Android\android-sdk.
If you see the following error dialog on launch, see Android Emulator Troubleshooting for workaround
instructions:
Before you can use the Android Device Manager, you must install Android SDK tools version 26.1.1 or later. If
Android SDK tools 26.1.1 or later is not installed, you may see this error dialog on launch:
If you see this error dialog, click Open SDK Manager to open the Android SDK Manager. In the Android SDK
Manager, click the Tools tab and install the following:
Android SDK Tools 26.1.1 or later
Android SDK Platform -Tools 27.0.1 or later
Android SDK Build-Tools 27.0.3 or later
These packages should be shown with Installed status as seen in the following screenshot:
After these packages are installed, you can close the SDK Manager and re-launch the Android Device Manager.
Main Screen
When you first launch the Android Device Manager, it presents a screen that displays all currently-configured
virtual devices. For each device, the Name, Operating System (Android API Level), CPU, Memory size, and
screen resolution are displayed:
When you click a device in the list, the Start button appears on the right. You can click the Start button to launch
the emulator with this virtual device:
After the emulator starts with the selected virtual device, the Start button changes to a Stop button that you can
use to halt the emulator:
New Device
To create a new device, click the New button (located in the upper right-hand area of the screen):
2. Select a system image to use with this virtual device by clicking the System image pull-down menu. This
menu lists the installed system device manager images under Installed. The Download section lists
system device manager images that are currently unavailable on your development computer but can be
automatically installed:
3. Give the device a new name. In the following example, the new device is named Nexus 5 API 25:
4. Edit any properties that you need to modify. To make changes to properties, see Editing Android Virtual
Device Properties.
5. Add any additional properties that you need to explicitly set. The New Device screen lists only the most
commonly-modified properties, but you can click the Add Property pull-down menu (in the bottom left-
hand corner) to add additional properties. In the following example, the hw.lcd.backlight property is being
added:
6. Click the Create button (lower right-hand corner) to create the new device:
7. You might get a License Acceptance screen. Click Accept if you agree to the license terms:
8. The Android Device Manager adds the new device to the list of installed virtual devices while displaying a
Creating progress indicator during device creation:
9. When the creation process is complete, the new device is shown in the list of installed virtual devices with a
Start button, ready to launch:
Edit Device
To edit an existing virtual device, select the device and click the Edit button (located in the upper right-hand corner
of the screen):
Clicking Edit launches the Device Editor for the selected virtual device:
The Device Editor screen lists the properties of the virtual device in the first column, with the corresponding
values of each property in the second column. When you select a property, a detailed description of that property
is displayed on the right.
For example, in the following screenshot the hw.lcd.density property is being changed from 420 to 240:
After you have made the necessary configuration changes, click the Save button. For more information about
changing virtual device properties, see Editing Android Virtual Device Properties.
Additional Options
Additional options for working with devices are available from the … menu in the upper right-hand corner:
Factory Reset – Resets the selected device to its default settings, erasing any user changes made to the
internal state of the device while it was running (this also erases the current Quick Boot snapshot, if any).
This change does not alter modifications that you make to the virtual device during creation and editing. A
dialog box will appear with the reminder that this reset cannot be undone. Click Wipe user data to confirm
the reset.
Delete – Permanently deletes the selected virtual device. A dialog box will appear with the reminder that
deleting a device cannot be undone. Click Delete if you are certain that you want to delete the device.
Troubleshooting
The following sections explain how to diagnose and work around problems that may occur when using the
Android Device Manager to configure virtual devices.
Visual Studio
Visual Studio for Mac
Android SDK in Non-Standard Location
Typically, the Android SDK is installed at the following location:
C:\Program Files (x86)\Android\android-sdk
If the SDK is not installed at this location, you may get this error when you launch the Android Device Manager:
To work around this problem, do the following:
1. From the Windows desktop, navigate to
C:\Users\username\AppData\Roaming\XamarinDeviceManager:
2. Double-click to open one of the log files and locate the Config file path. For example:
After making this change to user.config, you should be able to launch the Android Device Manager.
Snapshot disables WiFi on Android Oreo
If you have an AVD configured for Android Oreo with simulated Wi-Fi access, restarting the AVD after a snapshot
may cause Wi-Fi access to become disabled.
To work around this problem,
1. Select the AVD in the Android Device Manager.
2. From the additional options menu, click Reveal in Explorer.
3. Navigate to snapshots > default_boot.
4. Delete the snapshot.pb file:
Summary
This guide introduced the Android Device Manager available in Visual Studio for Mac and Visual Studio Tools for
Xamarin. It explained essential features such as starting and stopping the Android emulator, selecting an Android
virtual device (AVD ) to run, creating new virtual devices, and how to edit a virtual device. It explained how to edit
profile hardware properties for further customization, and it provided troubleshooting tips for common problems.
Related Links
Changes to the Android SDK Tooling
Debugging on the Android Emulator
SDK Tools Release Notes (Google)
avdmanager
sdkmanager
Editing Android Virtual Device Properties
6/4/2018 • 15 minutes to read • Edit Online
This article explains how to use the Android Device Manager to edit the profile properties of an Android virtual
device.
Visual Studio
Visual Studio for Mac
The Android Device Manager supports the editing of individual Android virtual device profile properties. The
New Device and Device Edit screens list the properties of the virtual device in the first column, with the
corresponding values of each property in the second column (as seen in this example):
When you select a property, a detailed description of that property is displayed on the right. You can modify
hardware profile properties and AVD properties. Hardware profile properties (such as hw.ramSize and
hw.accelerometer ) describe the physical characteristics of the emulated device. These characteristics include
screen size, the amount of available RAM, whether or not an accelerometer is present. AVD properties specify the
operation of the AVD when it runs. For example, AVD properties can be configured to specify how the AVD uses
your development computer's graphics card for rendering.
You can change properties by using the following guidelines:
To change a boolean property, click the check mark to the right of the boolean property:
To change an enum (enumerated) property, click the down-arrow to the right of the property and choose a
new value.
To change a string or integer property, double-click the current string or integer setting in the value column
and enter a new value.
The following table provides a detailed explanation of the properties listed in the New Device and Device
Editor screens:
abi.type ABI type – Specifies the ABI x86, x86_64, armeabi-v7a, arm64-v8a
(application binary interface) type of
the emulated device. The x86 option is
for the instruction set commonly
referred to as "x86" or "IA-32." The
x86_64 option is for the 64-bit x86
instruction set. The armeabi-v7a
option is for the ARM instruction set
with v7-a ARM extensions. The arm64-
v8a option is for the ARM instruction
set that supports AArch64.
hw.gpu.mode GPU emulation mode – Determines auto, host, mesa, angle, swiftshader, off
how GPU emulation is implemented by
the emulator. If you select auto, the
emulator will choose hardware and
software acceleration based on your
development computer setup. If you
select host, the emulator will use your
development computer's graphics
processor to perform GPU emulation
for faster rendering. If your GPU is not
compatible with the emulator and you
are on Windows, you can try angle
instead of host. The angle mode uses
DirectX to provide performance similar
to host. If you select mesa, the
emulator will use the Mesa 3D software
library to render graphics. Select mesa
if you have problems rendering via
your development computer's graphics
processor. The swiftshader mode can be
used to render graphics in software
with slightly less performance than
using your computer's GPU. The off
option (disable graphics hardware
emulation) is a deprecated option that
can cause improper rendering for some
items and is therefore not
recommended.
PROPERTY DESCRIPTION OPTIONS
hw.lcd.density LCD density – The density of the 120, 160, 240, 213, 320
emulated LCD display, measured in
density-independent pixels, or dp (dp is
a virtual pixel unit). When the setting is
160 dp, each dp corresponds to one
physical pixel. At runtime, Android uses
this value to select and scale the
appropriate resources/assets for correct
display rendering.
PROPERTY DESCRIPTION OPTIONS
hw.screen Touch screen type – Defines the type touch, multi-touch, no-touch
of screen on the emulated device. A
multi-touch screen can track two or
more fingers on the touch interface. A
touch screen can detect only single-
finger touch events. A no-touch screen
does not detect touch events.
For more information about these properties, see Hardware Profile Properties.
Android Emulator Troubleshooting
7/17/2018 • 7 minutes to read • Edit Online
In this article, the most common warning messages and issues that occur while configuring and running the
Android Emulator are described, along with workarounds and tips.
Performance Warnings
Visual Studio
Visual Studio for Mac
Beginning with Visual Studio 2017 version 15.4, a performance warning dialog may be displayed when you first
deploy your app to the Android Emulator. These warning dialogs are explained below.
Computer Does Not Contain an Intel Procesor
When this dialog is displayed, your computer does not have an Intel processor, which is required for acceleration
of the Android SDK Emulator. If your computer does not have an Intel processor, we recommend using a physical
Android device for development.
Hyper-V Is Installed or Active
When this dialog is displayed, Hyper-V is installed or active and must be disabled. Disabling Hyper-V explains how
to resolve this issue.
HAXM is Not Installed
This dialog indicates that your computer has an Intel processor, Hyper-V is disabled, but HAXM is not installed.
Installing HAXM describes the steps for installing HAXM.
HAXM Process Not Running
This dialog is displayed if your computer has an Intel processor, Hyper-V is disabled, Intel HAXM is installed, but
the HAXM process is not running. To resolve this issue, open a Command Prompt window and enter the following
command:
sc query intelhaxm
If the HAXM process is running, you should see output similar to the following:
SERVICE_NAME: intelhaxm
TYPE : 1 KERNEL_DRIVER
STATE : 4 RUNNING
(STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
If STATE is not set to RUNNING , see How to Use the Intel Hardware Accelerated Execution Manager to resolve the
problem.
Other Failures
This dialog is displayed if your computer has an Intel processor, Hyper-V is disabled, Intel HAXM is installed, the
HAXM process is running, but the emulator fails to start for some unknown reason. To help resolve this error, see
How to Use the Intel Hardware Accelerated Execution Manager.
Disabling Performance Warnings
If you would rather not see performance warnings, you can disable them. In Visual Studio, click Tools > Options
> Xamarin > Android Settings and disable the Warn if AVD acceleration is not supported (HAXM ) option:
Deployment Issues
If you get an error about a failure to install the APK on the emulator or a failure to run the Android Debug Bridge
(adb), verify that the Android SDK can connect to your emulator. To do this, use the following steps:
1. Launch the emulator from the Android Device Manager (select your virtual device and click Start).
2. Open a Command Prompt and go to the folder where adb is installed. For example, on Windows, this
might be at: C:\Program Files (x86)\Android\android-sdk\platform -tools\adb.exe.
3. Type the following command:
adb devices
4. If the emulator is accessible from the Android SDK, the emulator should appear in the list of attached
devices. For example:
5. If the emulator does not appear in this list, start the Android SDK Manager, apply all updates, then try
launching the emulator again.
HAXM Issues
Visual Studio
Visual Studio for Mac
If the Android Emulator does not start properly, this is often caused by problems with HAXM. HAXM issues are
often the result of conflicts with other virtualization technologies, incorrect settings, or an out of date HAXM driver.
HAXM Virtualization Conflicts
HAXM can conflict with other technologies that use virtualization, such as Hyper-V, Windows Device Guard, and
some antivirus software:
Hyper-V – If you are using a version of Windows before the Windows 10 April 2018 update (build
1803) and Hyper-V is enabled, follow the steps in Disabling Hyper-V.
Device Guard – Device Guard and Credential Guard can prevent Hyper-V from being disabled on
Windows machines. To disable Device Guard and Credential Guard, see Disabling Device Guard.
Antivirus Software – If you are running antivirus software that uses hardware-assisted virtualization (such
as Avast), disable or uninstall this software, reboot, and retry the Android SDK Emulator.
Incorrect BIOS Settings
If you are using HAXM on a Windows PC, HAXM will not work unless virtualization technology (Intel VT-x) is
enabled in the BIOS. If VT-x is disabled, you will get an error similiar to the following when you attempt to start
the Android Emulator:
This computer meets the requirements for HAXM, but Intel Virtualization Technology (VT-x) is not
turned on.
To correct this error, boot the computer into the BIOS, enable both VT-x and SL AT (Second Level Address
Translation), then restart the computer back into Windows.
Disabling Hyper-V
If you are using a version of Windows before the Windows 10 April 2018 Update (build 1803) and Hyper-V is
enabled, you must disable Hyper-V and reboot your computer to install and use HAXM. If you are using
Windows 10 April 2018 Update (build 1803) or later, Android Emulator version 27.2.7 or later can use Hyper-V
(instead of HAXM ) for hardware acceleration, so it is not necessary to disable Hyper-V.
You can disable Hyper-V from the Control Panel by following these steps:
1. In the Windows search box, enter Programs and then click the Programs and Features search result.
2. In the Control Panel Programs and Features dialog, click Turn Windows features on or off:
Intel HAXM and Microsoft Hyper-V cannot both be active at the same time. Unfortunately, there is no way to
switch between between Hyper-V and HAXM without restarting your computer.
In some cases, using the above steps will not succeed in disabling Hyper-V if Device Guard and Credential Guard
are enabled. If you are unable to disable Hyper-V (or it seems to be disabled but HAXM installation still fails), use
the steps in the next section to disable Device Guard and Credential Guard.
Disabling Device Guard
Device Guard and Credential Guard can prevent Hyper-V from being disabled on Windows machines. This is
often a problem for domain-joined machines that are configured and controlled by an owning organization. On
Windows 10, use the following steps to see if Device Guard is running:
1. In Windows Search, type System info to start the System Information app.
2. In the System Summary, look to see if Device Guard Virtualization based security is present and is in
the Running state:
4. Change Turn On Virtualization Based Security to Disabled (as shown above) and exit the Local Group
Policy Editor.
5. In the Windows Search Box, type cmd. When Command Prompt appears in the search results, right-click
Command Prompt and select Run as Administrator.
6. Copy and paste the following commands into the command prompt window (if drive Z: is in use, pick an
unused drive letter to use instead):
mountvol Z: /s
copy %WINDIR%\System32\SecConfig.efi Z:\EFI\Microsoft\Boot\SecConfig.efi /Y
bcdedit /create {0cb3b571-2f2e-4343-a879-d86a476d7215} /d "DebugTool" /application osloader
bcdedit /set {0cb3b571-2f2e-4343-a879-d86a476d7215} path "\EFI\Microsoft\Boot\SecConfig.efi"
bcdedit /set {bootmgr} bootsequence {0cb3b571-2f2e-4343-a879-d86a476d7215}
bcdedit /set {0cb3b571-2f2e-4343-a879-d86a476d7215} loadoptions DISABLE-LSA-ISO,DISABLE-VBS
bcdedit /set {0cb3b571-2f2e-4343-a879-d86a476d7215} device partition=Z:
mountvol Z: /d
7. Restart your computer. On the boot screen, you should see a prompt like the following:
Do you want to disable Credential Guard?
Press the indicated key to disable Credential Guard as prompted.
8. After the computer reboots, check again to ensure that Hyper-V is disabled (as described in the previous
steps).
If Hyper-V is still not disabled, the policies of your domain-joined computer may prevent you from disabling
Device Guard or Credential Guard. In this case, you can request an exemption from your domain adminstrator to
allow you to opt out of Credential Guard. Alternately, you can use a computer that is not domain-joined to use
HAXM.
Set Up Device for Development
6/25/2018 • 6 minutes to read • Edit Online
This article will discuss how to setup an Android device and connect it to a computer so that the device may be
used to run and debug Xamarin.Android applications.
By now, you've probably seen your great new application running on the Android emulator, and want to see it
running on your shiny Android device. Here are the steps involved with connecting a device to a computer for
debugging:
1. Enable Debugging on the Device - By default, it will not be possible to debug applications on a Android
device.
2. Install USB Drivers - This step is not necessary for OS X computers. Windows computers may require
the installation of USB drivers.
3. Connect the Device to the Computer - The final step involves connecting the device to the computer by
either USB or WiFi.
Each of these steps will be covered in more detail in the sections below.
Once the Developer Options tab is available under Settings > System, open it to reveal developer settings:
This is the place to enable developer options such as USB debugging and stay awake mode.
NOTE
These are the steps to set up a Google Nexus device and are provided as a reference. Steps for your specific device may
vary, but will follow a similar pattern. Search the internet for your device if you have trouble.
Run the android.bat application in the [Android SDK install path]\tools directory. By default, the
Xamarin.Android installer will put the Android SDK in following location on a Windows computer:
C:\Users\[username]\AppData\Local\Android\android-sdk
Check the Google USB Driver box, and click the Install button. The driver files are downloaded to the following
location:
C:\Users\[username]\AppData\Local\Android\android-sdk\extras\google\usb_driver
Installing the USB Driver
After the USB drivers are downloaded, it is necessary to install them. To install the drivers on Windows 7:
1. Connect your device to the computer with a USB cable.
2. Right-click on the Computer from your desktop or Windows Explorer, and select Manage .
3. Select Devices in the left pane.
4. Locate and expand Other Devices in the right pane.
5. Right-click the device name and select Update Driver Software . This will launch the Hardware Update
Wizard.
6. Select Browse my computer for driver software and click Next .
7. Click Browse and locate the USB driver folder (the Google USB driver is located in [Android SDK install
path]\extras\google\usb_driver).
8. Click Next to install the driver.
Installing Unverified Drivers in Windows 8
Extra steps may be required to install an unverified driver in Windows 8. The following steps describe how to
install the drivers for a Galaxy Nexus:
1. Access the Windows 8 Advanced Boot Options - This step involves rebooting the computer to access
the Advanced Boot Options. Start up a command line prompt and reboot the computer by using the
following command:
shutdown.exe /r /o
After this command is issued, your computer will not be able to listen to devices that are connected via
USB.
4. Disconnect the USB cable connecting your device to your computer.
5. Configure ADB so that it will connect to your Android device on the port that was specified in step 1
above:
Once this command finished the Android device is connected to the computer via WiFi.
When you're done debugging via WiFi, it is possible reset ADB back to USB mode with the following command:
adb usb
It is possible to ask ADB to list the devices that are connected to the computer. Regardless of how the devices are
connected, you can issue the following command at the command prompt to see what is connected:
adb devices
Summary
This article discussed how to configure an Android device for development by enabling debugging on the device.
It also covered how to connect the device to a computer using either USB or WiFi.
Related Links
Android Debug Bridge
Using Hardware Devices
Samsung Driver Downloads
OEM USB Drivers
Google USB Driver
XDA Developers : Windows 8 - ADB/fastboot driver problem solved
Microsoft's OpenJDK Distribution Preview
7/25/2018 • 2 minutes to read • Edit Online
This guide describes the steps for switching to the preview release of Microsoft's distribution of the OpenJDK.
Overview
Beginning with Visual Studio 15.9 and Visual Studio for Mac 7.7, Visual Studio Tools for Xamarin will move from
Oracle’s JDK to a lightweight version of the OpenJDK that is intended solely for Android development:
Download
To get started, download the correct build for your system:
Mac – https://dl.xamarin.com/OpenJDK/mac/microsoft-dist-openjdk-1.8.0.9.zip
Windows x86 – https://dl.xamarin.com/OpenJDK/win32/microsoft-dist-openjdk-1.8.0.9.zip
Windows x64 – https://dl.xamarin.com/OpenJDK/win64/microsoft-dist-openjdk-1.8.0.9.zip
Configure
Unzip to the correct location:
Mac – $HOME/Library/Developer/Xamarin/jdk/microsoft_dist_openjdk_1.8.0.9
Windows – C:\Program Files\Android\jdk\microsoft_dist_openjdk_1.8.0.9
IMPORTANT
This example uses build 1.8.0.9; however, the version you download may be newer.
Windows – Click Tools > Options > Xamarin > Android Settings and change the Java Development Kit
Location to the full path of the OpenJDK installation. In the following example, this path is set to C:\Program
Files\Android\jdk\microsoft_dist_openjdk_1.8.0.9:
Revert
To revert to the Oracle JDK, change the Java SDK location to the previously-used Oracle JDK path and rebuild the
solution. On Mac, you can revert to the Oracle JDK path by clicking Reset to Defaults.
If you have any problems with the Microsoft OpenJDK distribution, please report issues by using the feedback tool
in your IDE so that they can be tracked and corrected quickly.
Summary
In this article, you learned how to configure your IDE to use the preview release of Microsoft's OpenJDK
distribution, which is slated for stable release later in 2018.
Hello, Android
7/25/2018 • 2 minutes to read • Edit Online
In this two -part guide, you will build your first Xamarin.Android application using Visual Studio for Mac or Visual
Studio and develop an understanding of the fundamentals of Android application development with Xamarin.
Along the way, the tools, concepts, and steps required to build and deploy a Xamarin.Android application will be
introduced.
Part 1: Quickstart
In the first part of this guide you'll create an application that translates an alphanumeric phone number entered
by the user into a numeric phone number, and then calls that number.
Related Links
Android Getting Started
Debugging in Visual Studio
Visual Studio for Mac Recipes - Debugging
Hello, Android: Quickstart
7/20/2018 • 14 minutes to read • Edit Online
In this two -part guide, you will build your first Xamarin.Android application (using Visual Studio or Visual Studio
for Mac) and develop an understanding of the fundamentals of Android application development with Xamarin.
Along the way, you will be introduced to the tools, concepts, and steps required to build and deploy a
Xamarin.Android application.
Requirements
To follow along with this walkthrough, you will need the following:
Visual Studio
Visual Studio for Mac
Windows 7 or later.
Visual Studio 2015 Professional or later.
This walkthrough assumes that the latest version of Xamarin.Android is installed and running on your platform
of choice. For a guide to installing Xamarin.Android, refer to the Xamarin.Android Installation guides. Before you
get started, please download and unzip the Xamarin App Icons & Launch Screens set.
Configuring Emulators
If you are using the Android emulator, we recommend that you configure the emulator to use hardware
acceleration. Instructions for configuring hardware acceleration are available in Hardware Acceleration for
Emulator Performance.
Walkthrough
Visual Studio
Visual Studio for Mac
Start Visual Studio. Click File > New > Project to create a new project.
In the New Project dialog, click the Android App template. Name the new project Phoneword . Click OK:
In the New Android App dialog, click Blank App and click OK to create the new project:
Creating the Layout
After the new project is created, expand the Resources folder and then the layout folder in the Solution
Explorer. Double-click activity_main.axml to open it in the Android Designer. This is the layout file for the
app's screen:
From the Toolbox (the area on the left), enter text into the search field and drag a Text (Large) widget onto
the design surface (the area in the center):
With the Text (Large) control selected on the design surface, use the Properties pane to change the text
property of the Text (Large) widget to Enter a Phoneword: as shown here:
Drag a Plain Text widget from the Toolbox to the design surface and place it underneath the Text (Large)
widget:
With the Plain Text widget selected on the design surface, use the Properties pane to change the id property
of the Plain Text widget to @+id/PhoneNumberText and change the text property to 1-855-XAMARIN :
Drag a Button from the Toolbox to the design surface and place it underneath the Plain Text widget:
With the Button selected on the design surface, use the Properties pane to change the id property of the
Button to @+id/TranslateButton and change the text property to Translate :
Drag a TextView from the Toolbox to the design surface and place it under the Button widget. Set the id
property of the TextView to @+id/TranslatedPhoneWord and change the text to an empty string:
Save your work by pressing CTRL+S.
Writing Translation Code
The next step is to add some code to translate phone numbers from alphanumeric to numeric. Add a new file to
the project by right-clicking the Phoneword project in the Solution Explorer pane and choosing Add > New
Item... as shown below:
In the Add New Item dialog, select Visual C# > Code > Code File and name the new code file
PhoneTranslator.cs:
This creates a new empty C# class. Insert the following code into this file:
using System.Text;
using System;
namespace Core
{
public static class PhonewordTranslator
{
public static string ToNumber(string raw)
{
if (string.IsNullOrWhiteSpace(raw))
return "";
else
raw = raw.ToUpperInvariant();
Save the changes to the PhoneTranslator.cs file by clicking File > Save (or by pressing CTRL+S ), then close
the file.
Wiring up the Interface
The next step is to add code to wire up the user interface by inserting backing code into the MainActivity class.
Begin by wiring up the Translate button. In the MainActivity class, find the OnCreate method. The next step is
to add the button code inside OnCreate , below the base.OnCreate(bundle) and
SetContentView (Resource.Layout.Main) calls. First, modify the template code so that the OnCreate method
resembles the following:
using System;
using Android.App;
using Android.Content;
using Android.Widget;
using Android.OS;
namespace Phoneword
{
[Activity (Label = "Phone Word", MainLauncher = true)]
public class MainActivity : Activity
{
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
Get a reference to the controls that were created in the layout file via the Android Designer. Add the following
code inside the OnCreate method, after the call to SetContentView :
Add code that responds to user presses of the Translate button. Add the following code to the OnCreate method
(after the lines added in the previous step):
Save your work by selecting File > Save All (or by pressing CTRL -SHIFT-S ) and build the application by
selecting Build > Rebuild Solution (or by pressing CTRL -SHIFT-B ).
If there are errors, go through the previous steps and correct any mistakes until the application builds
successfully. If you get a build error such as, Resource does not exist in the current context, verify that the
namespace name in MainActivity.cs matches the project name ( Phoneword ) and then completely rebuild the
solution. If you still get build errors, verify that you have installed the latest Xamarin.Android updates.
Setting the Label and App Icon
You should now have a working application – it's time to add the finishing touches! In MainActivity.cs, edit the
Label for the MainActivity . The Label is what Android displays at the top of the screen to let users know
where they are in the application. At the top of the MainActivity class, change the Label to Phone Word as
shown here:
namespace Phoneword
{
[Activity (Label = "Phone Word", MainLauncher = true)]
public class MainActivity : Activity
{
...
}
}
Now it's time to set the application icon. By default, Visual Studio will provide a default icon for the project. Let's
delete these files from the solution, and replace them with a different icon. Expand the Resources folder in the
Solution Pad. Notice that there are five folders that are prefixed with mipmap-, and that each of these folders
contains a single Icon.png file:
It is necessary to delete each of these icon files from the project. Right click on each of Icon.png files, and select
Delete from the context menu:
Click on the Delete button in the dialog.
Next, download and unzip Xamarin App Icons set. This zip file holds the icons for the application. Each icon is
visually identical but at different resolutions it renders correctly on different devices with different screen
densities. The set of files must be copied into the Xamarin.Android project. In Visual Studio, in the Solution
Explorer, right-click the mipmap-hdpi folder and select Add > Existing Items:
From the selection dialog, navigate to the unzipped Xamarin AdApp Icons directory and open the mipmap-hdpi
folder. Select Icon.png and click Add.
Repeat these steps for each of the mipmap- folders until the contents of the mipmap- Xamarin App Icons
folders are copied to their counterpart mipmap- folders in the Phoneword project.
After all the icons are copied to the Xamarin.Android project, open the Project Options dialog by right clicking
on the project in the Solution Pad. Select Build > Android Application and select **@mipmap/icon** from
the Application icon combo box:
Congratulations on completing your first Xamarin.Android application! Now it's time to dissect the tools and
skills you have just learned. Next up is the Hello, Android Deep Dive.
Related Links
Xamarin Android App Icons (ZIP )
Phoneword (sample)
Hello, Android: Deep Dive
7/25/2018 • 17 minutes to read • Edit Online
In this two -part guide, you'll build your first Xamarin.Android application and develop an understanding of the
fundamentals of Android application development with Xamarin. Along the way, you will be introduced to the
tools, concepts, and steps required to build and deploy a Xamarin.Android application.
A Solution called Phoneword was created and the Android project Phoneword was placed inside of it.
Look at the items inside the Project to see each folder and its purpose:
Properties – Contains the AndroidManifest.xml file that describes all of the requirements for the
Xamarin.Android application, including name, version number, and permissions. The Properties folder also
houses AssemblyInfo.cs, a .NET assembly metadata file. It is a good practice to fill this file with some basic
information about your application.
References – Contains the assemblies required to build and run the application. If you expand the
References directory, you'll see references to .NET assemblies such as System, System.Core, and
System.Xml, as well as a reference to Xamarin's Mono.Android assembly.
Assets – Contains the files the application needs to run including fonts, local data files, and text files. Files
included here are accessible through the generated Assets class. For more information on Android Assets,
see the Xamarin Using Android Assets guide.
Resources – Contains application resources such as strings, images, and layouts. You can access these
resources in code through the generated Resource class. The Android Resources guide provides more
details about the Resources directory. The application template also includes a concise guide to Resources
in the AboutResources.txt file.
Resources
The Resources directory contains four folders named drawable, layout, mipmap and values, as well as a file
named Resource.designer.cs.
The items are summarized in the table below:
drawable – The drawable directories house drawable resources such as images and bitmaps.
mipmap – The mipmap directory holds drawable files for different launcher icon densities. In the default
template, the drawable directory houses the application icon file, Icon.png.
layout – The layout directory contains Android designer files (.axml) that define the user interface for each
screen or Activity. The template creates a default layout called Main.axml.
values – This directory houses XML files that store simple values such as strings, integers, and colors. The
template creates a file to store string values called Strings.xml.
Resource.designer.cs – Also known as the Resource class, this file is a partial class that holds the unique
IDs assigned to each resource. It is automatically created by the Xamarin.Android tools and is regenerated
as necessary. This file should not be manually edited, as Xamarin.Android will overwrite any manual
changes made to it.
Since there is no linear progression through an Android application (you can launch the application from several
points), Android has a unique way of keeping track of what classes and files make up an application. In the
Phoneword example, all the parts that make up the application are registered with a special XML file called the
Android Manifest. The role of the Android Manifest is to keep track of an application's contents, properties,
and permissions and to disclose them to the Android operating system. You can think of the Phoneword
application as a single Activity (screen) and a collection of resource and helper files tied together by the Android
Manifest file, as illustrated by the diagram below:
The next few sections explore the relationships between the various parts of the Phoneword application; this
should provide you with a better understanding of the diagram above. This exploration begins with the user
interface as it discusses the Android designer and layout files.
User Interface
Main.axml is the user interface layout file for the first screen in the application. The .axml indicates that this is an
Android designer file (AXML stands for Android XML). The name Main is arbitrary from Android's point of view –
the layout file could have been named something else. When you open Main.axml in the IDE, it brings up the
visual editor for Android layout files called the Android Designer:
Visual Studio
Visual Studio for Mac
In the Phoneword app, the TranslateButton's ID is set to @+id/TranslateButton :
Visual Studio
Visual Studio for Mac
When you set the id property of the TranslateButton, the Android Designer maps the TranslateButton control
to the Resource class and assigns it a resource ID of TranslateButton . This mapping of visual control to class
makes it possible to locate and use the TranslateButton and other controls in app code. This will be covered in
more detail when you break apart the code that powers the controls. All you need to know for now is that the code
representation of a control is linked to the visual representation of the control in the designer via the id property.
Source View
Everything defined on the design surface is translated into XML for Xamarin.Android to use. The Android
Designer provides a source view that contains the XML that was generated from the visual designer. You can view
this XML by switching to the Source panel in the lower left of the designer view, as illustrated by the screenshot
below:
Visual Studio
Visual Studio for Mac
This XML source code should contain the Text (Large), Plain Text, and the two Button elements. For a more in-
depth tour of the Android Designer, refer to the Xamarin Android Designer Overview guide.
The tools and concepts behind the visual part of the user interface have now been covered. Next, it's time to jump
into the code that powers the user interface as Activities and the Activity Lifecycle are explored.
The Activity Attribute registers the Activity with the Android Manifest; this lets Android know that this class is
part of the Phoneword application managed by this manifest. The Label property sets the text that will be
displayed at the top of the screen.
The MainLauncher property tells Android to display this Activity when the application starts up. This property
becomes important as you add more Activities (screens) to the application as explained in the Hello, Android
Multiscreen guide.
Now that the basics of MainActivity have been covered, it's time to dive deeper into the Activity code by
introducing the Activity Lifecycle.
Activity Lifecycle
In Android, Activities go through different stages of a lifecycle depending on their interactions with the user.
Activities can be created, started and paused, resumed and destroyed, and so on. The Activity class contains
methods that the system calls at certain points in the screen's lifecycle. The following diagram illustrates a typical
life of an Activity as well as some of the corresponding lifecycle methods:
By overriding Activity lifecycle methods, you can control how the Activity loads, how it reacts to the user, and
even what happens after it disappears from the device screen. For example, you can override the lifecycle methods
in the diagram above to perform some important tasks:
OnCreate – Creates views, initializes variables, and performs other prep work that must be done before the
user sees the Activity. This method is called only once when the Activity is loaded into memory.
OnResume – Performs any tasks that must happen every time the Activity returns to the device screen.
OnPause – Performs any tasks that must happen every time the Activity leaves the device screen.
When you add custom code to a lifecycle method in the Activity , you override that lifecycle method's base
implementation. You tap into the existing lifecycle method (which has some code already attached to it), and you
extend that method with your own code. You call the base implementation from inside your method to ensure that
the original code runs before your new code. An example of this is illustrated in the next section.
The Activity Lifecycle is an important and complex part of Android. If you'd like to learn more about Activities
after you finish the Getting Started series, read the Activity Lifecycle guide. In this guide, the next focus is the first
stage of the Activity Lifecycle, OnCreate .
OnCreate
Android calls the Activity 's OnCreate method when it creates the Activity (before the screen is presented to the
user). You can override the OnCreate lifecycle method to create views and prepare your Activity to meet the user:
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
In the Phoneword app, the first thing to do in OnCreate is load the user interface created in the Android
Designer. To load the UI, call SetContentView and pass it the resource layout name for the layout file: Main.axml .
The layout is located at Resource.Layout.Main :
SetContentView (Resource.Layout.Main);
When MainActivity starts up, it creates a view that is based on the contents of the Main.axml file. Note that the
layout file name is matched to the Activity name – Main.axml is the layout for MainActivity. This isn't required
from Android's point of view, but as you begin to add more screens to the application, you'll find that this naming
convention makes it easier to match the code file to the layout file.
After the layout file is prepared, you can start looking up controls. To look up a control, call FindViewById and pass
in the resource ID of the control:
Now that you have references to the controls in the layout file, you can start programming them to respond to
user interaction.
Responding to User Interaction
In Android, the Click event listens for the user's touch. In this app, the Click event is handled with a lambda, but
a delegate or a named event handler could be used instead. The final TranslateButton code resembled the
following:
In this two -part guide, you expand the Phoneword application that you created in the Hello, Android guide to
handle a second screen. Along the way, this guide will introduce the basic Android Application Building Blocks and
dive deeper into Android architecture as you develop a better understanding of Android application structure and
functionality.
Part 1: Quickstart
In the first part of this guide, you'll add a second screen to the Phoneword application to keep track of the history
of numbers called from the app. The final app will display a second screen that lists the call history.
Related Links
Android Getting Started
Debugging in Visual Studio
Visual Studio for Mac Recipes - Debugging
Hello, Android Multiscreen: Quickstart
5/1/2018 • 6 minutes to read • Edit Online
This two -part guide expands the Phoneword application to handle a second screen. Along the way, basic Android
Application Building Blocks are introduced with a deeper dive into Android architecture.
The accompanying Deep Dive reviews what was built and discusses architecture, navigation, and other new
Android concepts encountered along the way.
Requirements
Because this guide picks up where Hello, Android leaves off, it requires completion of the Hello, Android
Quickstart. If you would like to jump directly into the walkthrough below, you can download the completed
version of Phoneword (from the Hello, Android Quickstart) and use it to start the walkthrough.
Walkthrough
In this walkthrough you'll add a Translation History screen to the Phoneword application.
Visual Studio
Visual Studio for Mac
Start by opening the Phoneword application in Visual Studio and editing the Main.axml file from the Solution
Explorer.
Updating the Layout
From the Toolbox, drag a Button onto the design surface and place it below the TranslatedPhoneWord
TextView. In the Properties pane, change the button Id to @+id/TranslationHistoryButton
Set the Text property of the button to @string/translationHistory . The Android Designer will interpret this
literally, but you're going to make a few changes so that the button's text shows up correctly:
Expand the values node under the Resources folder in the Solution Explorer and double-click the string
resources file, Strings.xml:
Add the translationHistory string name and value to the Strings.xml file and save it:
The Translation History button text should update to reflect the new string value:
With the Translation History button selected on the design surface, find the enabled setting in the Properties
pane and set its value to false to disable the button. This will cause the button to become darker on the design
surface:
Creating the Second Activity
Create a second Activity to power the second screen. In the Solution Explorer, right-click the Phoneword
project and choose Add > New Item...:
In the Add New Item dialog, choose Visual C# > Activity and name the Activity file
TranslationHistoryActivity.cs.
Replace the template code in TranslationHistoryActivity.cs with the following:
using System;
using System.Collections.Generic;
using Android.App;
using Android.OS;
using Android.Widget;
namespace Phoneword
{
[Activity(Label = "@string/translationHistory")]
public class TranslationHistoryActivity : ListActivity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Create your application here
var phoneNumbers = Intent.Extras.GetStringArrayList("phone_numbers") ?? new string[0];
this.ListAdapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1,
phoneNumbers);
}
}
}
In this class, you're creating a ListActivity and populating it programmatically, so you don't need to create a new
layout file for this Activity. This is discussed in more detail in the Hello, Android Multiscreen Deep Dive.
Adding Translation History Code
This app collects phone numbers (that the user has translated on the first screen) and passes them to the second
screen. The phone numbers are stored as a list of strings. To support lists (and Intents, which are used later), add
the following using directives to the top of MainActivity.cs:
using System.Collections.Generic;
using Android.Content;
Next, create an empty list that can be filled with phone numbers. The MainActivity class will look like this:
In the MainActivity class, add the following code to register the Translation History button (place this line after
the translateButton declaration):
Add the following code to the end of the OnCreate method to wire up the Translation History button:
Update the Translate button to add the phone number to the list of phoneNumbers . The Click handler for the
TranslateHistoryButton should resemble the following code:
Save and build the application to make sure there are no errors.
Running the App
Deploy the application to an emulator or device. The following screenshots illustrate the running Phoneword
application:
Congratulations on completing your first multi-screen Xamarin.Android application! Now it's time to dissect the
tools and skills you just learned – next up is the Hello, Android Multiscreen Deep Dive.
Related Links
Xamarin App Icons & Launch Screens (ZIP )
Phoneword (sample)
PhonewordMultiscreen (sample)
Hello, Android Multiscreen: Deep Dive
4/12/2018 • 6 minutes to read • Edit Online
In this two -part guide, the basic Phoneword application (created in the Hello, Android guide) is expanded to
handle a second screen. Along the way, the basic Android Application Building Blocks are introduced. A deeper
dive into Android architecture is included to help you develop a better understanding of Android application
structure and functionality.
Android Navigation
Intents were used to navigate between screens. It's time to dive into this code to see how Intents work and
understand their role in Android navigation.
Launching a Second Activity with an Intent
In the Phoneword application, an Intent was used to launch a second screen (Activity). Start by creating an Intent,
passing in the current Context ( this , referring to the current Context) and the type of Application Block that
you're looking for ( TranslationHistoryActivity ):
The Context is an interface to global information about the application environment – it lets newly-created
objects know what's going on with the application. If you think of an Intent as a message, you are providing the
name of the message recipient ( TranslationHistoryActivity ) and the receiver's address ( Context ).
Android provides an option to attach simple data to an Intent (complex data is handled differently). In the
Phoneword example, PutStringArrayExtra is used to attach a list of phone numbers to the Intent and
StartActivity is called on the recipient of the Intent. The completed code looks like this:
For more information on string resources and other Android resources, refer to the Android Resources guide.
ListView and ArrayAdapter – A ListView is a UI component that provides a simple way to present a scrolling list
of rows. A ListView instance requires an Adapter to feed it with data contained in row views. The following line
of code was used to populate the user interface of TranslationHistoryActivity :
ListViews and Adapters are beyond the scope of this document, but they are covered in the very comprehensive
ListViews and Adapters guide. Populating a ListView With Data deals specifically with using built-in ListActivity
and ArrayAdapter classes to create and populate a ListView without defining a custom layout, as was done in the
Phoneword example.
Summary
Congratulations, you've completed your first multi-screen Android application! This guide introduced Android
Application Building Blocks and Intents and used them to build a multi-screened Android application. You now
have the solid foundation you need to start developing your own Xamarin.Android applications.
Next, you'll learn to build cross-platform applications with Xamarin in the Building Cross-Platform Applications
guides.
Xamarin for Java Developers
6/20/2018 • 24 minutes to read • Edit Online
If you are a Java developer, you are well on your way to leveraging your skills and existing code on the Xamarin
platform while reaping the code reuse benefits of C#. You will find that C# syntax is very similar to Java syntax,
and that both languages provide very similar features. In addition, you'll discover features unique to C# that will
make your development life easier.
Overview
This article provides an introduction to C# programming for Java developers, focusing primarily on the C#
language features that you will encounter while developing Xamarin.Android applications. Also, this article
explains how these features differ from their Java counterparts, and it introduces important C# features (relevant
to Xamarin.Android) that are not available in Java. Links to additional reference material are included, so you can
use this article as a "jumping off" point for further study of C# and .NET.
If you are familiar with Java, you will feel instantly at home with the syntax of C#. C# syntax is very similar to Java
syntax – C# is a "curly brace" language like Java, C, and C++. In many ways, C# syntax reads like a superset of Java
syntax, but with a few renamed and added keywords.
Many key characteristics of Java can be found in C#:
Class-based object-oriented programming
Strong typing
Support for interfaces
Generics
Garbage collection
Runtime compilation
Both Java and C# are compiled to an intermediate language that is run in a managed execution environment. Both
C# and Java are statically-typed, and both languages treat strings as immutable types. Both languages use a
single-rooted class hierarchy. Like Java, C# supports only single inheritance and does not allow for global
methods. In both languages, objects are created on the heap using the new keyword, and objects are garbage-
collected when they are no longer used. Both languages provide formal exception handling support with try /
catch semantics. Both provide thread management and synchronization support.
However, there are many differences between Java and C#. For example:
Java does not support implicitly-typed local variables (C# supports the var keyword).
In Java, you can pass parameters only by value, while in C# you can pass by reference as well as by value.
(C# provides the ref and out keywords for passing parameters by reference; there is no equivalent to
these in Java).
Java does not support preprocessor directives like #define .
Java does not support unsigned integer types, while C# provides unsigned integer types such as ulong ,
uint , ushort and byte .
Java does not support operator overloading; in C# you can overload operators and conversions.
In a Java switch statement, code can fall through into the next switch section, but in C# the end of every
switch section must terminate the switch (the end of each section must close with a break statement).
In Java, you specify the exceptions thrown by a method with the throws keyword, but C# has no concept of
checked exceptions – the throws keyword is not supported in C#.
C# supports Language-Integrated Query (LINQ ), which lets you use the reserved words from , select ,
and where to write queries against collections in a way that is similar to database queries.
Of course, there are many more differences between C# and Java than can be covered in this article. Also, both
Java and C# continue to evolve (for example, Java 8, which is not yet in the Android toolchain, supports C#-style
lambda expressions) so these differences will change over time. Only the most important differences currently
encountered by Java developers new to Xamarin.Android are outlined here.
Going from Java to C# Development provides an introduction to the fundamental differences between C#
and Java.
Object-Oriented Programming Features outlines the most important object-oriented feature differences
between the two languages.
Keyword Differences provides a table of useful keyword equivalents, C#-only keywords, and links to C#
keyword definitions.
C# brings many key features to Xamarin.Android that are not currently readily available to Java developers on
Android. These features can help you to write better code in less time:
Properties – With C#'s property system, you can access member variables safely and directly without
having to write setter and getter methods.
Lambda Expressionss – In C# you can use anonymous methods (also called lambdas) to express your
functionality more succinctly and more efficiently. You can avoid the overhead of having to write one-time-
use objects, and you can pass local state to a method without having to add parameters.
Event Handling – C# provides language-level support for event-driven programming, where an object can
register to be notified when an event of interest occurs. The event keyword defines a multicast broadcast
mechanism that a publisher class can use to notify event subscribers.
Asynchronous Programming – The asynchronous programming features of C# ( async / await ) keep apps
responsive. The language-level support of this feature makes async programming easy to implement and
less error-prone.
Finally, Xamarin allows you to leverage existing Java assets via a technology known as binding. You can call your
existing Java code, frameworks, and libraries from C# by making use of Xamarin's automatic binding generators.
To do this, you simply create a static library in Java and expose it to C# via a binding.
namespace WeatherApp
{
...
Importing Types
When you make use of types defined in external namespaces, you import these types with a using statement
(which is very similar to the Java import statement). In Java, you might import a single type with a statement like
the following:
import javax.swing.JButton
You might import an entire Java package with a statement like this:
import javax.swing.*
The C# using statement works in a very similar way, but it allows you to import an entire package without
specifying a wildcard. For example, you will often see a series of using statements at the beginning of
Xamarin.Android source files, as seen in this example:
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using System.Net;
using System.IO;
using System.Json;
using System.Threading.Tasks;
These statements import functionality from the System , Android.App , Android.Content , etc. namespaces.
Generics
Both Java and C# support generics, which are placeholders that let you plug in different types at compile time.
However, generics work slightly differently in C#. In Java, type erasure makes type information available only at
compile time, but not at run time. By contrast, the .NET common language runtime (CLR ) provides explicit support
for generic types, which means that C# has access to type information at runtime. In day-to-day Xamarin.Android
development, the importantance of this distinction is not often apparent, but if you are using reflection, you will
depend on this feature to access type information at run time.
In Xamarin.Android, you will often see the generic method FindViewById used to get a reference to a layout
control. This method accepts a generic type parameter that specifies the type of control to look up. For example:
In this code example, FindViewById gets a reference to the TextView control that is defined in the layout as Label,
then returns it as a TextView type.
For more information about generics, see the MSDN Generics topic. Note that there are some limitations in
Xamarin.Android support for generic C# classes; for more information, see Limitations.
In this example, SensorsActivity inherits from Activity and implements the functionality declared in the
ISensorEventListener interface. Note that the list of interfaces must come after the base class (or you will get a
compile-time error). By convention, C# interface names are prepended with an upper-case "I"; this makes it
possible to determine which classes are interfaces without requiring an implements keyword.
When you want to prevent a class from being further subclassed in C#, you precede the class name with sealed –
in Java, you precede the class name with final .
For more about C# class definitions, see the MSDN Classes and Structs and Inheritance topics.
Properties
In Java, mutator methods (setters) and inspector methods (getters) are often used to control how changes are
made to class members while hiding and protecting these members from outside code. For example, the Android
TextView class provides getText and setText methods. C# provides a similar but more direct mechanism known
as properties. Users of a C# class can access a property in the same way as they would access a field, but each
access actually results in a method call that is transparent to the caller. This "under the covers" method can
implement side effects such as setting other values, performing conversions, or changing object state.
Properties are often used for accessing and modifying UI (user interface) object members. For example:
In this example, width and height values are read from the rulerView object by accessing its MeasuredWidth and
MeasuredHeight properties. When these properties are read, values from their associated (but hidden) field values
are fetched behind the scenes and returned to the caller. The rulerView object may store width and height values
in one unit of measurement (say, pixels) and convert these values on-the-fly to a different unit of measurement
(say, millimeters) when the MeasuredWidth and MeasuredHeight properties are accessed.
The rulerView object also has a property called DrawingCacheEnabled – the example code sets this property to
true to enable the drawing cache in rulerView . Behind the scenes, an associated hidden field is updated with the
new value, and possibly other aspects of rulerView state are modified. For example, when DrawingCacheEnabled is
set to false , rulerView may also erase any drawing cache information already accumulated in the object.
Access to properties can be read/write, read-only, or write-only. Also, you can use different access modifiers for
reading and writing. For example, you can define a property that has public read access but private write access.
For more information about C# properties, see the MSDN Properties topic.
Calling Base Class Methods
To call a base-class constructor in C#, you use a colon ( : ) followed by the base keyword and an initializer list;
this base constructor call is placed immediately after the derived constructor parameter list. The base-class
constructor is called on entry to the derived constructor; the compiler inserts the call to the base constructor at the
start of the method body. The following code fragment illustrates a base constructor called from a derived
constructor in a Xamarin.Android app:
public class PictureLayout : ViewGroup
{
...
public class PictureLayout (Context context)
: base (context)
{
...
}
...
}
In this example, the PictureLayout class is derived from the ViewGroup class. The PictureLayout constructor
shown in this example accepts a context argument and passes it to the ViewGroup constructor via the
base(context) call.
To call a base-class method in C#, use the base keyword. For example, Xamarin.Android apps often make calls to
base methods as shown here:
In this case, the OnCreate method defined by the derived class ( MainActivity ) calls the OnCreate method of the
base class ( Activity ).
Access Modifiers
Java and C# both support the public , private , and protected access modifiers. However, C# supports two
additional access modifiers:
internal – The class member is accessible only within the current assembly.
protected internal – The class member is accessible within the defining assembly, the defining class, and
derived classes (derived classes both inside and outside the assembly have access).
For more information about C# access modifiers, see the MSDN Access Modifiers topic.
Virtual and Override Methods
Both Java and C# support polymorphism, the ability to treat related objects in the same manner. In both
languages, you can use a base-class reference to refer to a derived-class object, and the methods of a derived class
can override the methods of its base classes. Both languages have the concept of a virtual method, a method in a
base class that is designed to be replaced by a method in a derived class. Like Java, C# supports abstract classes
and methods.
However, there are some differences between Java and C# in how you declare virtual methods and override them:
In C#, methods are non-virtual by default. Parent classes must explicitly label which methods are to be
overridden by using the virtual keyword. By contrast, all methods in Java are virtual methods by default.
To prevent a method from being overridden in C#, you simply leave off the virtual keyword. By contrast,
Java uses the final keyword to mark a method with "override is not allowed."
C# derived classes must use the override keyword to explicitly indicate that a virtual base-class method is
being overridden.
For more information about C#'s support for polymorphism, see the MSDN Polymorphism topic.
Lambda Expressions
C# makes it possible to create closures: inline, anonymous methods that can access the state of the method in
which they are enclosed. Using lambda expressions, you can write fewer lines of code to implement the same
functionality that you might have implemented in Java with many more lines of code.
Lambda expressions make it possible for you to skip the extra ceremony involved in creating a one-time-use class
or anonymous class as you would in Java – instead, you can just write the business logic of your method code
inline. Also, because lambdas have access to the variables in the surrounding method, you don't have to create a
long parameter list to pass state to your method code.
In C#, lambda expressions are created with the => operator as shown here:
In Xamarin.Android, lambda expressions are often used for defining event handlers. For example:
In this example, the lambda expression code (the code within the curly braces) increments a click count and
updates the button text to display the click count. This lambda expression is registered with the button object as
a click event handler to be called whenever the button is tapped. (Event handlers are explained in more detail
below.) In this simple example, the sender and args parameters are not used by the lambda expression code, but
they are required in the lambda expression to meet the method signature requirements for event registration.
Under the hood, the C# compiler translates the lambda expression into an anonymous method that is called
whenever button click events take place.
For more information about C# and lambda expressions, see the MSDN Lambda Expressions topic.
Event Handling
An event is a way for an object to notify registered subscribers when something interesting happens to that object.
Unlike in Java, where a subscriber typically implements a Listener interface that contains a callback method, C#
provides language-level support for event handling through delegates. A delegate is like an object-oriented type-
safe function pointer – it encapsulates an object reference and a method token. If a client object wants to subscribe
to an event, it creates a delegate and passes the delegate to the notifying object. When the event occurs, the
notifying object invokes the method represented by the delegate object, notifying the subscribing client object of
the event. In C#, event handlers are essentially nothing more than methods that are invoked through delegates.
For more information about delegates, see the MSDN Delegates topic.
In C#, events are multicast; that is, more than one listener can be notified when an event takes place. This
difference is observed when you consider the syntactical differences between Java and C# event registration. In
Java you call SetXXXListener to register for event notifications; in C# you use the += operator to register for
event notifications by "adding" your delegate to the list of event listeners. In Java, you call SetXXXListener to
unregister, while in C# you use the -= to "subtract" your delegate from the list of listeners.
In Xamarin.Android, events are often used for notifying objects when a user does something to a UI control.
Normally, a UI control will have members that are defined using the event keyword; you attach your delegates to
these members to subscribe to events from that UI control.
To subscribe to an event:
1. Create a delegate object that refers to the method that you want to be invoked when the event occurs.
2. Use the += operator to attach your delegate to the event you are subscribing to.
The following example defines a delegate (with an explicit use of the delegate keyword) to subscribe to button
clicks. This button-click handler starts a new activity:
startActivityButton.Click += delegate {
Intent intent = new Intent (this, typeof (MyActivity));
StartActivity (intent);
};
However, you also can use a lambda expression to register for events, skipping the delegate keyword altogether.
For example:
In this example, the startActivityButton object has an event that expects a delegate with a certain method
signature: one that accepts sender and event arguments and returns void. However, because we don't want to go to
the trouble to explicitly define such a delegate or its method, we declare the signature of the method with
(sender, e) and use a lambda expression to implement the body of the event handler. Note that we have to
declare this parameter list even though we aren't using the sender and e parameters.
It is important to remember that you can unsubscribe a delegate (via the -= operator), but you cannot
unsubscribe a lambda expression – attempting to do so can cause memory leaks. Use the lambda form of event
registration only when your handler will not unsubscribe from the event.
Typically, lambda expressions are used to declare event handlers in Xamarin.Android code. This shorthand way to
declare event handlers may seem cryptic at first, but it saves an enormous amount of time when you are writing
and reading code. With increasing familiarity, you become accustomed to recognizing this pattern (which occurs
frequently in Xamarin.Android code), and you spend more time thinking about the business logic of your
application and less time wading through syntactical overhead.
Asynchronous Programming
Asynchronous programming is a way to improve the overall responsiveness of your application. Asynchronous
programming features make it possible for the rest of your app code to continue running while some part of your
app is blocked by a lengthy operation. Accessing the web, processing images, and reading/writing files are
examples of operations that can cause an entire app to appear to freeze up if it is not written asynchronously.
C# includes language-level support for asynchronous programming via the async and await keywords. These
language features make it very easy to write code that performs long-running tasks without blocking the main
thread of your application. Briefly, you use the async keyword on a method to indicate that the code in the
method is to run asynchronously and not block the caller's thread. You use the await keyword when you call
methods that are marked with async . The compiler interprets the await as the point where your method
execution is to be moved to a background thread (a task is returned to the caller). When this task completes,
execution of the code resumes on the caller's thread at the await point in your code, returning the results of the
async call. By convention, methods that run asynchronously have Async suffixed to their names.
In Xamarin.Android applications, async and await are typically used to free up the UI thread so that it can
respond to user input (such as the tapping of a Cancel button) while a long-running operation takes place in a
background task.
In the following example, a button click event handler causes an asynchronous operation to download an image
from the web:
downloadButton.Click += downloadAsync;
...
async void downloadAsync(object sender, System.EventArgs e)
{
webClient = new WebClient ();
var url = new Uri ("http://photojournal.jpl.nasa.gov/jpeg/PIA15416.jpg");
byte[] bytes = null;
In this example, when the user clicks the downloadButton control, the downloadAsync event handler creates a
WebClient object and a Uri object to fetch an image from the specifed URL. Next, it calls the WebClient object's
DownloadDataTaskAsync method with this URL to retrieve the image.
Notice that the method declaration of downloadAsync is prefaced by the async keyword to indicate that it will run
asynchronously and return a task. Also note that the call to DownloadDataTaskAsync is preceded by the await
keyword. The app moves the execution of the event handler (starting at the point where await appears) to a
background thread until DownloadDataTaskAsync completes and returns. Meanwhile, the app's UI thread can still
respond to user input and fire event handlers for the other controls. When DownloadDataTaskAsync completes
(which may take several seconds), execution resumes where the bytes variable is set to the result of the call to
DownloadDataTaskAsync , and the remainder of the event handler code displays the downloaded image on the
caller's (UI) thread.
For an introduction to async / await in C#, see the MSDN Asynchronous Programming with Async and Await
topic. For more information about Xamarin support of asynchronous programming features, see Async Support
Overview.
Keyword Differences
Many language keywords used in Java are also used in C#. There are also a number of Java keywords that have an
equivalent but differently-named counterpart in C#, as listed in this table:
JAVA C# DESCRIPTION
Also, there are many keywords that are unique to C# and have no counterpart in Java. Xamarin.Android code
often makes use of the following C# keywords (this table is useful to refer to when you are reading through
Xamarin.Android sample code):
C# DESCRIPTION
Summary
This article provided an introduction to the Xamarin.Android C# programming environment from a Java
developer's perspective. It pointed out the similarities between C# and Java while explaining their practical
differences. It introduced assemblies and namespaces, explained how to import external types, and provided an
overview of the differences in access modifiers, generics, class derivation, calling base-class methods, method
overriding, and event handling. It introduced C# features that are not available in Java, such as properties, async /
await asynchronous programming, lambdas, C# delegates, and the C# event handling system. It included tables
of important C# keywords, explained how to interoperate with existing Java libraries, and provided links to related
documentation for further study.
Related Links
Java Integration Overview
C# Programming Guide
C# Reference
Moving to C# and the .NET Framework, for Java Developers
Xamarin.Android Application Fundamentals
5/2/2018 • 3 minutes to read • Edit Online
This section provides a guide on some of the more common things tasks or concepts that developers need to be
aware of when developing Android applications.
Accessibility
This page describes how to use the Android Accessibility APIs to build apps according to the accessibility checklist.
Resources in Android
This article introduces the concept of Android resources in Xamarin.Android and documents how to use them. It
covers how to use resources in your Android application to support application localization, and multiple devices
including varying screen sizes and densities.
Activity Lifecycle
Activities are a fundamental building block of Android Applications and they can exist in a number of different
states. The activity lifecycle begins with instantiation and ends with destruction, and includes many states in
between. When an activity changes state, the appropriate lifecycle event method is called, notifying the activity of
the impending state change and allowing it to execute code to adapt to that change. This article examines the
lifecycle of activities and explains the responsibility that an activity has during each of these state changes to be
part of a well-behaved, reliable application.
Localization
This article explains how to localize a Xamarin.Android into other languages by translating strings and providing
alternate images.
Services
This article covers Android services, which are Android components that allow work to be done in the background.
It explains the different scenarios that services are suited for and shows how to implement them both for
performing long-running background tasks as well as to provide an interface for remote procedure calls.
Broadcast Receivers
This guide covers how to create and use broadcast receivers, an Android component that responds to system-wide
broadcasts, in Xamarin.Android.
Permissions
You can use the tooling support built into Visual Studio for Mac or Visual Studio to create and add permissions to
the Android Manifest. This document describes how to add permissions in Visual Studio and Xamarin Studio.
CPU Architectures
Xamarin.Android supports several CPU architectures, including 32-bit and 64-bit devices. This article explains how
to target an app to one or more Android-supported CPU architectures.
Handling Rotation
This article describes how to handle device orientation changes in Xamarin.Android. It covers how to work with the
Android resource system to automatically load resources for a particular device orientation as well as how to
programmatically handle orientation changes. Then it describes techniques for maintaining state when a device is
rotated.
Android Audio
The Android OS provides extensive support for multimedia, encompassing both audio and video. This guide
focuses on audio in Android and covers playing and recording audio using the built-in audio player and recorder
classes, as well as the low -level audio API. It also covers working with Audio events broadcast by other
applications, so that developers can build well-behaved applications.
Notifications
This section explains how to implement local and remote notifications in Xamarin.Android. It describes the various
UI elements of an Android notification and discusses the API's involved with creating and displaying a notification.
For remote notifications, both Google Cloud Messaging and Firebase Cloud Messaging are explained. Step-by-
step walkthroughs and code samples are included.
Touch
This section explains the concepts and details of implementing touch gestures on Android. Touch APIs are
introduced and explained followed by an exploration of gesture recognizers.
This page describes how to use the Android Accessibility APIs to build apps according to the accessibility checklist.
Refer to the iOS accessibility and OS X accessibility pages for other platform APIs.
Describing UI Elements
Android provides a ContentDescription property that is used by screen reading APIs to provide an accessible
description of the control's purpose.
The content description can be set in either C# or in the AXML layout file.
C#
The description can be set in code to any string (or a string resource):
AXML layout
In XML layouts use the android:contentDescription attribute:
<ImageButton
android:id=@+id/saveButton"
android:src="@drawable/save_image"
android:contentDescription="Save data" />
someText.Hint = "Enter some text"; // displays (and is "read") when control is empty
AXML layout
In XML layout files use the android:hint attribute:
<EditText
android:id="@+id/someText"
android:hint="Enter some text" />
AXML layout
In layout XML use the android:labelFor property to reference another control's identifier:
<TextView
android:id="@+id/labelFirstName"
android:hint="Enter some text"
android:labelFor="@+id/editFirstName" />
<EditText
android:id="@+id/editFirstName"
android:hint="Enter some text" />
button.Click += delegate {
button.Text = string.Format ("{0} clicks!", count++);
button.AnnounceForAccessibility (button.Text);
};
label.Focusable = false;
AXML layout
In layout XML files set the android:focusable attribute:
<android:focusable="false" />
You can also control focus order with the nextFocusDown , nextFocusLeft , nextFocusRight , nextFocusUp attributes,
typically set in the layout AXML. Use these attributes to ensure the user can navigate easily through the controls
on the screen.
Accessibility and Localization
In the examples above the hint and content description are set directly to the display value. It is preferable to use
values in a Strings.xml file, such as this:
Using text from a strings file is shown below in C# and AXML layout files:
C#
Instead of using string literals in code, look up translated values from strings files with Resources.GetText :
AXML
In layout XML accessibility attributes like hint and contentDescription can be set to a string identifier:
<TextView
android:id="@+id/someText"
android:hint="@string/enter_info" />
<ImageButton
android:id=@+id/saveButton"
android:src="@drawable/save_image"
android:contentDescription="@string/save_info" />
The benefit of storing text in a separate file is multiple language translations of the file can be provided in your app.
See the Android localization guide to learn how add localized string files to an application project.
Testing Accessibility
Follow these steps to enable TalkBack and Explore by Touch to test accessibility on Android devices.
You may need to install TalkBack from Google Play if it does not appear in Settings > Accessibility.
Related Links
Cross-platform Accessibility
Android Accessibility APIs
Understanding Android API Levels
7/3/2018 • 18 minutes to read • Edit Online
Xamarin.Android has several Android API level settings that determine your app's compatibility with multiple
versions of Android. This guide explains what these settings mean, how to configure them, and what effect they
have on your app at run time.
Quick Start
Xamarin.Android exposes three Android API level project settings:
Target Framework – Specifies which framework to use in building your application. This API level is used
at compile time by Xamarin.Android.
Minimum Android Version – Specifies the oldest Android version that you want your app to support.
This API level is used at run time by Android.
Target Android Version – Specifies the version of Android that your app is intended to run on. This API
level is used at run time by Android.
Before you can configure an API level for your project, you must install the SDK platform components for that
API level. For more information about downloading and installing Android SDK components, see Android SDK
Setup.
NOTE
Beginning in August 2018, the Google Play Console will require that new apps target API level 26 (Android 8.0) or higher.
Existing apps will be required to target API level 26 or higher beginning in November 2018. For more information, see
Improving app security and performance on Google Play for years to come.
Visual Studio
Visual Studio for Mac
Normally, all three Xamarin.Android API levels are set to the same value. On the Application page, set
Compile using Android version (Target Framework) to the latest stable API version (or, at a minimum, to
the Android version that has all of the features you need). In the following screenshot, the Target Framework is
set to Android 7.1 (API Level 25 - Nougat):
On the Android Manifest page, set the Minimum Android version to Use Compile using SDK version and
set the Target Android version to the same value as the Target Framework version (in the following screenshot,
the Target Android Framework is set to Android 7.1 (Nougat)):
If you want to maintain backward compatibility with an earlier version of Android, set Minimum Android
version to target to the oldest version of Android that you want your app to support. (Note that API Level 14
is the minimum API level required for Google Play services and Firebase support.) The following example
configuration supports Android versions from API Level 14 thru API level 25:
If your app supports multiple Android versions, your code must include runtime checks to ensure that your app
works with the Minimum Android version setting (see Runtime Checks for Android Versions below for details).
If you are consuming or creating a library, see API Levels and Libraries below for best practices in configuring
API level settings for libraries.
API 26 (Android 8.0) – Oreo, released August 2017. Build version code Android.OS.BuildVersionCodes.O
API 25 (Android 7.1) – Nougat, released December 2016. Build version code
Android.OS.BuildVersionCodes.NMr1
API 24 (Android 7.0) – Nougat, released August 2016. Build version code
Android.OS.BuildVersionCodes.N
API 23 (Android 6.0) – Marshmallow, released August 2015. Build version code
Android.OS.BuildVersionCodes.M
API 22 (Android 5.1) – Lollipop, released March 2015. Build version code
Android.OS.BuildVersionCodes.LollipopMr1
API 21 (Android 5.0) – Lollipop, released November 2014. Build version code
Android.OS.BuildVersionCodes.Lollipop
API 20 (Android 4.4W ) – Kitkat Watch, released June 2014. Build version code
Android.OS.BuildVersionCodes.KitKatWatch
API 19 (Android 4.4) – Kitkat, released October 2013. Build version code
Android.OS.BuildVersionCodes.KitKat
API 18 (Android 4.3) – Jelly Bean, released July 2013. Build version code
Android.OS.BuildVersionCodes.JellyBeanMr2
API 17 (Android 4.2-4.2.2) – Jelly Bean, released November 2012. Build version code
Android.OS.BuildVersionCodes.JellyBeanMr1
API 16 (Android 4.1-4.1.1) – Jelly Bean, released June 2012. Build version code
Android.OS.BuildVersionCodes.JellyBean
API 15 (Android 4.0.3-4.0.4) – Ice Cream Sandwich, released December 2011. Build version code
Android.OS.BuildVersionCodes.IceCreamSandwichMr1
API 14 (Android 4.0-4.0.2) – Ice Cream Sandwich, released October 2011. Build version code
Android.OS.BuildVersionCodes.IceCreamSandwich
API 13 (Android 3.2) – Honeycomb, released June 2011. Build version code
Android.OS.BuildVersionCodes.HoneyCombMr2
API 12 (Android 3.1.x) – Honeycomb, released May 2011. Build version code
Android.OS.BuildVersionCodes.HoneyCombMr1
API 11 (Android 3.0.x) – Honeycomb, released February 2011. Build version code
Android.OS.BuildVersionCodes.HoneyComb
API 10 (Android 2.3.3-2.3.4) – Gingerbread, released February 2011. Build version code
Android.OS.BuildVersionCodes.GingerBreadMr1
API 9 (Android 2.3-2.3.2) – Gingerbread, released November 2010. Build version code
Android.OS.BuildVersionCodes.GingerBread
API 8 (Android 2.2.x) – Froyo, released June 2010. Build version code
Android.OS.BuildVersionCodes.Froyo
API 7 (Android 2.1.x) – Eclair, released January 2010. Build version code
Android.OS.BuildVersionCodes.EclairMr1
API 6 (Android 2.0.1) – Eclair, released December 2009. Build version code
Android.OS.BuildVersionCodes.Eclair01
API 5 (Android 2.0) – Eclair, released November 2009. Build version code
Android.OS.BuildVersionCodes.Eclair
API 4 (Android 1.6) – Donut, released September 2009. Build version code
Android.OS.BuildVersionCodes.Donut
API 3 (Android 1.5) – Cupcake, released May 2009. Build version code
Android.OS.BuildVersionCodes.Cupcake
API 2 (Android 1.1) – Base, released February 2009. Build version code
Android.OS.BuildVersionCodes.Base11
API 1 (Android 1.0) – Base, released October 2008. Build version code
Android.OS.BuildVersionCodes.Base
As this list indicates, new Android versions are released frequently – sometimes several releases per year. As a
result, the universe of Android devices that might run your app includes of a wide variety of older and newer
Android versions. How can you guarantee that your app will run consistently and reliably on so many different
versions of Android? Android's API levels can help you manage this problem.
Android API Levels
Each Android device runs at exactly one API level – this API level is guaranteed to be unique per Android
platform version. The API level precisely identifies the version of the API set that your app can call into; it
identifies the combination of manifest elements, permissions, etc. that you code against as a developer.
Android's system of API levels helps Android determine whether an application is compatible with an Android
system image prior to installing the application on a device.
When an application is built, it contains the following API level information:
The target API level of Android that the app is built to run on.
The minimum Android API level that an Android device must have to run your app.
These settings are used to ensure that the functionality needed to run the app correctly is available on the
Android device at installation time. If not, the app is blocked from running on that device. For example, if the API
level of an Android device is lower than the minimum API level that you specify for your app, the Android
device will prevent the user from installing your app.
Set the Target Framework by selecting an API level in the drop-down menu under Compile using Android
version as shown above.
Minimum Android Version
The Minimum Android version (also known as minSdkVersion ) is the oldest version of the Android OS (i.e., the
lowest API level) that can install and run your application. By default, an app can only be installed on devices
matching the Target Framework setting or higher; if the Minimum Android version setting is lower than the
Target Framework setting, your app can also run on earlier versions of Android. For example, if you set the
Target Framework to Android 7.1 (Nougat) and set the Minimum Android version to Android 4.0.3 (Ice
Cream Sandwich), your app can be installed on any platform from API level 15 to API level 25, inclusive.
Although your app may successfully build and install on this range of platforms, this does not guarantee that it
will successfully run on all of these platforms. For example, if your app is installed on Android 5.0 (Lollipop)
and your code calls an API that is available only in Android 7.1 (Nougat) and newer, your app will get a
runtime error and possibly crash. Therefore, your code must ensure – at runtime – that it calls only those APIs
that are supported by the Android device that it is running on. In other words, your code must include explicit
runtime checks to ensure that your app uses newer APIs only on devices that are recent enough to support
them. Runtime Checks for Android Versions, later in this guide, explains how to add these runtime checks to
your code.
Visual Studio
Visual Studio for Mac
To access the Minimum Android version setting in Visual Studio, open the project properties in Solution
Explorer and select the Android Manifest page. In the drop-down menu under Minimum Android version
you can select the Minimum Android version for your application:
If you select Use Compile using SDK version, the Minimum Android version will be the same as the Target
Framework setting.
Target Android Version
The Target Android Version (also known as targetSdkVersion ) is the API level of the Android device where the
app expects to run. Android uses this setting to determine whether to enable any compatibility behaviors – this
ensures that your app continues to work the way you expect. Android uses the Target Android version setting of
your app to figure out which behavior changes can be applied to your app without breaking it (this is how
Android provides forward compatibility).
The Target Framework and the Target Android version, while having very similar names, are not the same thing.
The Target Framework setting communicates target API level information to Xamarin.Android for use at
compile time, while the Target Android version communicates target API level information to Android for use at
run time (when the app is installed and running on a device).
Visual Studio
Visual Studio for Mac
To access this setting in Visual Studio, open the project properties in Solution Explorer and select the Android
Manifest page. In the drop-down menu under Target Android version you can select the Target Android
version for your application:
We recommend that you explicitly set the Target Android version to the latest version of Android that you use to
test your app. Ideally, it should be set to the latest Android SDK version – this allows you to use new APIs prior
to working through the behavior changes. For most developers, we do not recommend setting the Target
Android version to Use Compile using SDK version.
In general, the Target Android Version should be bounded by the Minimum Android Version and the Target
Framework. That is:
Minimum Android Version <= Target Android Version <= Target Framework
For more information about SDK levels, see the Android Developer uses-sdk documentation.
In this example, our app's Target Framework is set to Android 5.0 (API Level 21) and its Minimum Android
version is set to Android 4.1 (API Level 16). Because SetCategory is available in API level
Android.OS.BuildVersionCodes.Lollipop and later, this example code will call SetCategory only when it is actually
available – it will not attempt to call SetCategory when the API level is 16, 17, 18, 19, or 20. The functionality is
reduced on these earlier Android versions only to the extent that notifications are not sorted properly (because
they are not categorized by type), yet the notifications are still published to alert the user. Our app still works,
but its functionality is slightly diminished.
In general, the build version check helps your code decide at runtime between doing something the new way
versus the old way. For example:
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Lollipop)
{
// Do things the Lollipop way
}
else
{
// Do things the pre-Lollipop way
}
There's no fast and simple rule that explains how to reduce or modify your app's functionality when it runs on
older Android versions that are lacking one or more APIs. In some cases (such as in the SetCategory example
above), it's sufficient to simply omit the API call when it's not available. However, in other cases, you may need
to implement alternate functionality for when Android.OS.Build.VERSION.SdkInt is detected to be less than the
API level that your app needs to present its optimum experience.
The Minimum Android version and Target Android version settings are not available because the resulting
library is not a stand-alone app – the library could be run on any Android version, depending on the app that it
is packaged with. You can specify how the library is to be compiled, but you can't predict which platform API
level the library will be run on. With this in mind, the following best practices should be observed when
consuming or creating libraries:
When consuming an Android library – If you are consuming an Android library in your application,
be sure to set your app's Target Framework setting to an API level that is at least as high as the Target
Framework setting of the library.
When creating an Android library – If you are creating an Android library for use by other
applications, be sure to set its Target Framework setting to the minimum API level that it needs in order
to compile.
These best practices are recommended to help prevent the situation where a library attempts to call an API that
is not available at runtime (which can cause the app to crash). If you are a library developer, you should strive to
restrict your usage of API calls to a small and well-established subset of the total API surface area. Doing so
helps to ensure that your library can be used safely across a wider range of Android versions.
Summary
This guide explained how Android API levels are used to manage app compatibility across different versions of
Android. It provided detailed steps for configuring the Xamarin.Android Target Framework, Minimum Android
version, and Target Android version project settings. It provided instructions for using the Android SDK
Manager to install SDK packages, included examples of how to write code to deal with different API levels at
runtime, and explained how to manage API levels when creating or consuming Android libraries. It also
provided a comprehensive list that relates API levels to Android version numbers (such as Android 4.4),
Android version names (such as Kitkat), and Xamarin.Android build version codes.
Related Links
Android SDK Setup
SDK CLI Tooling Changes
Picking your compileSdkVersion, minSdkVersion, and targetSdkVersion
What is API Level?
Codenames, Tags, and Build Numbers
Android Resources
4/12/2018 • 2 minutes to read • Edit Online
This article introduces the concept of Android resources in Xamarin.Android and will document how to use them.
It covers how to use resources in your Android application to support application localization, and multiple
devices including varying screen sizes and densities.
Overview
An Android application is seldom just source code. There are often many other files that make up an application:
video, images, fonts, and audio files just to name a few. Collectively, these non-source code files are referred to as
resources and are compiled (along with the source code) during the build process and packaged as an APK for
distribution and installation onto devices:
This article will take a comprehensive look at using resources and cover the following topics:
Android Resource Basics – Using default resources programmatically and declaratively, adding resource
types such as images and fonts to an application.
Device Specific Configurations – Supporting the different screen resolutions and densities in an
application.
Localization – Using resources to support the different regions an application may be used.
Related Links
Using Android Assets
Application Fundamentals
Application Resources
Supporting Multiple Screens
Android Resource Basics
7/25/2018 • 4 minutes to read • Edit Online
Almost all Android applications will have some sort of resources in them; at a minimum they often have the user
interface layouts in the form of XML files. When a Xamarin.Android application is first created, default resources
are setup by the Xamarin.Android project template:
Visual Studio
Visual Studio for Mac
The five files that make up the default resources were created in the Resources folder:
Icon.png – The default icon for the application
Main.axml – The default user interface layout file for an application. Note that while Android uses the .xml
file extension, Xamarin.Android uses the .axml file extension.
Strings.xml – A string table to help with localization of the application
AboutResources.txt – This is not necessary and may safely be deleted. It just provides a high level
overview of the Resources folder and the files in it.
Resource.designer.cs – This file is automatically generated and maintained by Xamarin.Android and holds
the unique ID's assigned to each resource. This is very similar and identical in purpose to the R.java file that
an Android application written in Java would have. It is automatically created by the Xamarin.Android tools
and will be regenerated from time to time.
Each resource ID is contained inside a nested class that corresponds to the resource type. For example, when the
file Icon.png was added to the project, Xamarin.Android updated the Resource class, creating a nested class called
Drawable with a constant inside named Icon . This allows the file Icon.png to be referred to in code as
Resource.Drawable.Icon . The Resource class should not be manually edited, as any changes that are made to it will
be overwritten by Xamarin.Android.
When referencing resources programmatically (in code), they can be accessed via the Resources class hierarchy
which uses the following syntax:
@[<PackageName>.]Resource.<ResourceType>.<ResourceName>
PackageName – The package which is providing the resource and is only required when resources from
other packages are being used.
ResourceType – This is the nested resource type that is within the Resource class described above.
Resource Name – this is the filename of the resource (without the extension) or the value of the
android:name attribute for resources that are in an XML element.
@[<PackageName>:]<ResourceType>/<ResourceName>.
PackageName – the package which is providing the resource and is only required when resources from
other packages are being used.
ResourceType – This is the nested resource type that is within the Resource class.
Resource Name – this is the filename of the resource (without the file type extension) or the value of the
android:name attribute for resources that are in an XML element.
This example has an ImageView that requires a drawable resource named flag. The ImageView has its src
attribute set to **@drawable/flag**. When the activity starts, Android will look inside the directory
Resource/Drawable for a file named flag.png (the file extension could be another image format, like flag.jpg)
and load that file and display it in the ImageView . When this application is run, it would look something like the
following image:
Default Resources
4/12/2018 • 4 minutes to read • Edit Online
Default resources are items that are not specific to any particular device or form factor, and therefore are the
default choice by the Android OS if no more specific resources can be found. As such, they're the most common
type of resource to create. They're organized into sub-directories of the Resources directory according to their
resource type:
Visual Studio
Visual Studio for Mac
In the image above, the project has default values for drawable resources, layouts, and values (XML files that
contain simple values).
A complete list of resource types is provided below:
animator – XML files that describe property animations. Property animations were introduced in API level
11 (Android 3.0) and provides for the animation of properties on an object. Property animations are a more
flexible and powerful way to describe animations on any type of object.
anim – XML files that describe tween animations. Tween animations are a series of animation instructions
to perform transformations on the contents of a View object, or example, rotation an image or growing the
size of text. Tween animations are limited to only View objects.
color – XML files that describe a state list of colors. To understand color state lists, consider a UI widget such
as a Button. It may have different states such as pressed or disabled, and the button may change color with
each change in state. The list is expressed in a state list.
drawable – Drawable resources are a general concept for graphics that can be compiled into the application
and then accessed by API calls or referenced by other XML resources. Some examples of drawables are
bitmap files (.png, .gif, .jpg), special resizable bitmaps known as Nine-Patches, state lists, generic shapes
defined in XML, etc.
layout – XML files that describe a user interface layout, such as an activity or a row in a list.
menu – XML files that describe application menus such as Options Menus, Context Menus, and submenus.
For an example of menus, see the Popup Menu Demo or the Standard Controls sample.
raw – Arbitrary files that are saved in their raw, binary form. These files are compiled into an Android
application in a binary format.
values – XML files that contain simple values. An XML file in the values directory does not define a single
resource, but instead can define multiple resources. For example one XML file may hold a list of string
values, while another XML file may hold a list of color values.
xml – XML files that are similar in function to the .NET configuration files. These are arbitrary XML that can
be read at run time by the application
Alternate Resources
4/12/2018 • 8 minutes to read • Edit Online
Alternate resources are those resources that target a specific device or run-time configuration such as the current
language, particular screen size, or pixel density. If Android can match a resource that is more specific for a
particular device or configuration than the default resource, then that resource will be used instead. If it does not
find an alternate resource that matches the current configuration, then the default resources will be loaded. How
Android decides what resources will be used by an application will be covered in more detail below, in the section
Resource Location
Alternate resources are organized as a sub-directory inside the Resources folder according to the resource type,
just like default resources. The name of the alternate resource subdirectory is in the form: ResourceType-Qualifier
Qualifier is a name that identifies a specific device configuration. There may be more than one qualifier in a name,
each of them separated by a dash. For example, the screenshot below shows a simple project that has alternate
resources for various configurations such as locale, screen density, screen size, and orientation:
Visual Studio
Visual Studio for Mac
Screen Aspect – This is based on the aspect ratio, not the screen orientation. A long screen is wider. Added
in API level 4 (Android 1.6). Possible values are long and notlong.
Screen Orientation – Portrait or landscape screen orientation. This can change during the lifetime of an
application. Possible values are port and land .
Dock Mode – For devices in a car dock or a desk dock. Added in API level 8 (Android 2.2.x). Possible values
are car and desk .
Night Mode – Whether or not the application is running at night or in the day. This may change during the
lifetime of an application and is meant to give developers an opportunity to use darker versions of an
interface at night. Added in API level 8 (Android 2.2.x). Possible values are night and notnight .
Screen Pixel Density (dpi) – The number of pixels in a given area on the physical screen. Typically
expressed as dots per inch (dpi). Possible values are:
ldpi – Low density screens.
mdpi – Medium density screens
hdpi – High density screens
xhdpi – Extra high density screens
nodpi – Resources that are not to be scaled
tvdpi – Introduced in API level 13 (Android 3.2) for screens between mdpi and hdpi.
Touchscreen Type – Specifies the type of touchscreen a device may have. Possible values are notouch (no
touch screen), stylus (a resistive touchscreen suitable for a stylus), and finger (a touchscreen).
Keyboard Availability – Specifies what kind of keyboard is available. This may change during the lifetime
of an application – for example when a user opens a hardware keyboard. Possible values are:
keysexposed – The device has a keyboard available. If there is no software keyboard enabled, then
this is only used when the hardware keyboard is opened.
keyshidden – The device does have a hardware keyboard but it is hidden and no software keyboard
is enabled.
keyssoft – the device has a software keyboard enabled.
Primary Text Input Method – Use to specify what kinds of hardware keys are available for input. Possible
values are:
nokeys – There are no hardware keys for input.
qwerty – There is a qwerty keyboard available.
12key – There is a 12-key hardware keyboard
Navigation Key Availability – For when 5-way or d-pad (directional-pad) navigation is available. This can
change during the lifetime of your application. Possible values are:
navexposed – the navigational keys are available to the user
navhidden – the navigational keys are not available.
Primary Non-Touch Navigation Method – The kind of navigation available on the device. Possible
values are:
nonav – the only navigation facility available is the touch screen
dpad – a d-pad (directional-pad) is available for navigation
trackball – the device has a trackball for navigation
wheel – the uncommon scenario where there are one or more directional wheels available
Platform Version (API level) – The API level supported by the device in the format vN, where N is the
API level that is being targeted. For example, v11 will target an API level 11 (Android 3.0) device.
For more complete information about resource qualifiers see Providing Resources on the Android Developers
website.
When the system is looking for density-specific resources and cannot find them, it will attempt to locate other
density specific resources and scale them. Android may not necessarily use the default resources. For example,
when looking for a low -density resource and it is not available, Android may select high-density version of the
resource over the default or medium-density resources. It does this because the high-density resource can be
scaled down by a factor of 0.5, which will result in fewer visibility issues than scaling down a medium-density
resource which would require a factor of 0.75.
As an example, consider an application that has the following drawable resource directories:
drawable
drawable-en
drawable-fr-rCA
drawable-en-port
drawable-en-notouch-12key
drawable-en-port-ldpi
drawable-port-ldpi
drawable-port-notouch-12key
And now the application is run on a device with the following configuration:
Locale – en-GB
Orientation – port
Screen density – hdpi
Touchscreen type – notouch
Primary input method – 12key
To begin with, the French resources are eliminated as they conflict with the locale of en-GB , leaving us with:
drawable
drawable-en
drawable-en-port
drawable-en-notouch-12key
drawable-en-port-ldpi
drawable-port-ldpi
drawable-port-notouch-12key
Next, the first qualifier is selected from the qualifiers table above: MCC and MNC. There are no resource
directories that contain this qualifier so the MCC/MNC code is ignored.
The next qualifier is selected, which is Language. There are resources that match the language code. All resource
directories that do not match the language code of en are rejected, so that the list of resources is now:
drawable-en-port
drawable-en-notouch-12key
drawable-en-port-ldpi
The next qualifier that is present is for screen orientation, so all resource directories that do not match the screen
orientation of port are eliminated:
drawable-en-port
drawable-en-port-ldpi
Next is the qualifier for screen density, ldpi , which results in the exclusion of one more resource directory:
drawable-en-port-ldpi
As a result of this process, Android will use the drawable resources in the resource directory
drawable-en-port-ldpi for the device.
NOTE
The screen size qualifiers provide one exception to this selection process. It is possible for Android to select resources that are
designed for a smaller screen than what the current device provides. For example, a large screen device may use the
resources provide for a normal sized screen. However the reverse of this is not true: the same large screen device will not use
the resources provided for an xlarge screen. If Android cannot find a resource set that matches a given screen size, the
application will crash.
Creating Resources for Varying Screens
4/12/2018 • 7 minutes to read • Edit Online
Android itself runs on many different devices, each having a wide variety of resolutions, screen sizes, and screen
densities. Android will perform scaling and resizing to make your application work on these devices, but this may
result in a sub-optimal user experience. For example, images may appear blurry, images may occupy too much (or
not enough) screen space which causes the position of UI elements in the layout will overlap or be too far apart.
Concepts
A few terms and concepts are important to understand to support multiple screens.
Screen Size – The amount of physical space for displaying your application
Screen Density – The number of pixels in any given area on the screen. The typical unit of measure is dots
per inch (dpi).
Resolution – The total number of pixels on the screen. When developing applications, resolution is not as
important as screen size and density.
Density-independent pixel (dp) – This is a virtual unit of measure to allow layouts to be designed
independent of density. To convert dp into screen pixels the following formula is used:
px = dp × dpi ÷ 160
Orientation – The screen's orientation is considered to be landscape when it is wider than it is tall. In
contrast, portrait orientation is when the screen is taller than it is wide. The orientation can change during
the lifetime of an application as the user rotates the device.
Notice that the first three of these concepts are inter-related – increasing the resolution without increasing the
density will increase the screen size. However if both the density and resolution are increased then the screen size
can remain unchanged. This relationship between screen size, density and resolution complicate screen support
very quickly.
To help deal with this complexity, the Android framework prefers to use density-independent pixels (dp ) for screen
layouts. By using density independent pixels, UI elements will appear to the user to have the same physical size on
screens with different densities.
AndroidManifest.xml is added to the Properties directory. The file is then edited to include supports-screens:
The following is a comparison of how the older pre-API Level 13 screen size qualifiers compare to density-
independent pixels:
426dp x 320dp is small
470dp x 320dp is normal
640dp x 480dp is large
960dp x 720dp is xlarge
The newer screen size qualifiers in API level 13 and up have a higher precedence than the older screen qualifiers
of API levels 12 and lower. For applications that will span the old and the new API levels, it may be necessary to
create alternate resources using both sets of qualifiers as shown in the following screen shot:
Visual Studio
Visual Studio for Mac
This website will help with creation of bitmaps that target the four common screen densities by providing one
image. Android Asset Studio will then create the bitmaps with some customizations and then allow them to be
downloaded as a zip file.
Application localization is the act of providing alternate resources to target a specific region or locale. For example,
you might provide localized language strings for various countries, or you might change colors or layout to match
particular cultures. Android will load and use the resources appropriate for the device's locale at runtime time
without any changes to the source code.
For example, the image below shows the same application running in three different device locales, but the text
displayed in each button is specific to the locale that each device is set to:
In this example, the contents of a layout file, Main.axml looks something like this:
In the example above, the string for the button was loaded from the resources by providing the resource ID for the
string:
Visual Studio
Visual Studio for Mac
Localizing Android Apps
Read the Introduction to Localization for tips and guidance on localizing mobile apps.
The Localizing Android Apps guide contains more specific examples on how to translate strings and localize
images using Xamarin.Android.
Related Links
Localizing Android Apps
Cross-Platform Localization Overview
Using Android Assets
4/12/2018 • 2 minutes to read • Edit Online
Assets provide a way to include arbitrary files like text, xml, fonts, music, and video in your application. If you try to
include these files as "resources", Android will process them into its resource system and you will not be able to
get the raw data. If you want to access data untouched, Assets are one way to do it.
Assets added to your project will show up just like a file system that can read from by your application using
AssetManager. In this simple demo, we are going to add a text file asset to our project, read it using AssetManager ,
and display it in a TextView.
Selecting the correct BuildAction ensures that the file will be packaged into the APK at compile time.
Reading Assets
Assets are read using an AssetManager. An instance of the AssetManager is available by accessing the Assets
property on an Android.Content.Context , such as an Activity. In the following code, we open our read_asset.txt
asset, read the contents, and display it using a TextView.
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
Related Links
AssetManager
Context
Fonts
4/13/2018 • 11 minutes to read • Edit Online
Overview
Beginning with API level 26, the Android SDK allows fonts to be treated as resources, just like a layouts or
drawables. The Android Support Library 26 NuGet will backport the new font API's to those apps that target API
level 14 or higher.
After targetting API 26 or installing the Android Support Library v26, there are two ways to use fonts in an
Android application:
1. Package the font as an Android resource – this ensures that the font is always available to the application,
but will increase the size of the APK.
2. Download the fonts – Android also supports downloading a font from a font provider. The font provider
checks if the font is already on the device. If necessary, the font will be downloaded and cached on the device.
This font can be shared between multiple applications.
Similar fonts (or a font that may have several different styles) may be grouped into font families. This allows
developers to specify certain attributes of the font, such as it's weight, and Android will automatically select the
appropriate font from the font family.
The Android Support Library v26 will backport support for fonts to API level 26. When targeting the older API
levels, it is necessary to declare the app XML namespace and to name the various font attributes using the
android: namespace and the app: namespace. If only the android: namespace is used, then the fonts will not be
displayed devices running API level 25 or less. For example, this XML snippet declares a new font family resource
that will work in API level 14 and higher:
<font android:font="@font/sourcesanspro_regular"
android:fontStyle="normal"
android:fontWeight="400"
app:font="@font/sourcesanspro_regular"
app:fontStyle="normal"
app:fontWeight="400" />
</font-family>
As long as fonts are provided to an Android application in a proper way, they can be applied to a UI widget by
setting the fontFamily attribute. For example, the following snippet demonstrates how to display a font in a
TextView:
<TextView
android:text="The quick brown fox jumped over the lazy dog."
android:fontFamily="@font/sourcesanspro_regular"
app:fontFamily="@font/sourcesanspro_regular"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
This guide will first discuss how to use fonts as an Android resource, and then move on to discuss how to
download fonts at runtime.
Fonts as a Resource
Packaging a font into an Android APK ensures that it is always available to the application. A font file (either a .TTF
or a .OTF file) is added to a Xamarin.Android application just like any other resource, by copying files to a
subdirectory in the Resources folder of a Xamarin.Android project. Fonts resources are kept in a font sub-
directory of the Resources folder of the project.
NOTE
The fonts should have a Build Action of AndroidResource or they will not be packaged into the final APK. The build action
should be automatically set by the IDE.
When there are many similar font files (for example, the same font with different weights or styles) it is possible to
group them into a font family.
Font Families
A font family is a set of fonts that have different weights and styles. For example, there might be separate font files
for bold or italic fonts. The font family is defined by font elements in an XML file that is kept in the
Resources/font directory. Each font family should have it's own XML file.
To create a a font family, first add all the fonts to the Resources/font folder. Then create a new XML file in the font
folder for the font family. The name of the XML file has no affinity or relationship to the fonts being referenced; the
resource file can be any legal Android resource file name. This XML file will have a root font-family element that
contains one or more font elements. Each font element declares the attributes of a font.
The following XML is an example of a font family for the Sources Sans Pro font that defines many different font
weights. This is saved as file in the Resources/font folder named sourcesanspro.xml:
<TextView
android:text="Sans Source Pro semi-bold italic, 600 weight, italic"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="@font/sourcesanspro"
android:textAppearance="?android:attr/textAppearanceLarge"
android:gravity="center_horizontal"
android:fontWeight="600"
android:textStyle="italic"
/>
The GetFont method will automatically load the the first font within a font family. To load a font that matches a
specific style, use the Typeface.Create method. This method will try to load a font that matches the specified style.
As an example, this snippet will try to load a bold Typeface object from a font family that is defined in
Resources/fonts:
Downloading Fonts
Instead of packaging fonts as an application resource, Android can download fonts from a remote source. This will
have the desirable effect of reducing the size of the APK.
Fonts are downloaded with the assistance of a font provider. This is a specialized content provider that manages
the downloading and caching of fonts to all applications on the device. Android 8.0 includes a font provider to
download fonts from the Google Font Repository. This default font provider is backported to API level 14 with the
Android Support Library v26.
When an app makes a request for a font, the font provider will first check to see if the font is already on the device.
If not, it will then attempt to download the font. If the font cannot be downloaded, then Android will use the default
system font. Once the font has been downloaded, it is available to all applications on the device, not just the app
that made the initial request.
When a request is made to download a font, the app does not directly query the font provider. Instead, apps will
use an instance of the FontsContract API (or the FontsContractCompat if the Support Library 26 is being used).
Android 8.0 supports downloading fonts in two different ways:
1. Declare Downloadable Fonts as a Resource – An app may declare downloadable fonts to Android via XML
resource files. These files will contain all of the meta-data that Android needs to asynchronously download the
fonts when the app starts and cache them on the device.
2. Programmatically – APIs in Android API level 26 allow an application to download the fonts
programmatically, while the application is running. Apps will create a FontRequest object for a given font, and
pass this object to the FontsContract class. The FontsContract takes the FontRequest and retrieves the font
from a font provider. Android will synchronously download the font. An example of creating a FontRequest will
be shown later in this guide.
Regardless of which approach is used, resources files that must be added to the Xamarin.Android application
before fonts can be downloaded. First, the font(s) must be declared in an XML file in the Resources/font directory
as part of a font family. This snippet is an example of how to download fonts from the Google Fonts Open Source
collection using the default font provider that comes with Android 8.0 (or Support Library v26):
The font-family element contains the following attributes, declaring the information that Android requires to
download the fonts:
1. fontProviderAuthority – The authority of the Font Provider to be used for the request.
2. fontPackage – The package for the Font Provider to be used for the request. This is used to verify the identity
of the provider.
3. fontQuery – This is a string that will help the font provider locate the requested font. Details on the font query
are specific to the font provider. The QueryBuilder class in the Downloadable Fonts sample app provides some
information on the query format for fonts from the Google Fonts Open Source Collection.
4. fontProviderCerts – A resource array with the list of sets of hashes for the certificates that the provider should
be signed with.
Once the fonts are defined, it may be necessary to provide information about the font certificates involved with the
download.
Font Certificates
If the font provider is not preinstalled on the device, or if the app is using the Xamarin.Android.Support.Compat
library, Android requires the security certificates of the font provider. These certificates will be listed in an array
resource file that is kept in Resources/values directory.
For example, the following XML is named Resources/values/fonts_cert.xml and stores the certificates for the
Google font provider:
MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1U
EBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQ
EJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ
2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5k
cm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdG
Ns8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6
t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr2
2ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOj
gfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQs
wCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECx
MHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFM
AMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEB
ahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtA
WPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8n
fBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs=
</item>
</string-array>
<string-array name="com_google_android_gms_fonts_certs_prod">
<item>
MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQ
HEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4Mj
EyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3M
RQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCC
AQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRcz
fey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs
1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYX
tqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r
45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29
vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBA
UAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+
a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1Mvcy
UTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3W
fMBEmh/9iFBDAaTCK
</item>
</string-array>
</resources>
With these resource files in place, the app is capable of downloading the fonts.
Declaring Downloadable Fonts as Resources
By listing the downloadable fonts in the AndroidManifest.XML, Android will asynchronously download the fonts
when the app first starts. The font's themselves are listed in an array resource file, similar to this one:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<array name="downloadable_fonts" translatable="false">
<item>@font/vt323</item>
</array>
</resources>
To download these fonts, they have to be declared in AndroidManifest.XML by adding meta-data as a child of
the application element. For example, if the downloadable fonts are declared in a resource file at
Resources/values/downloadable_fonts.xml, then this snippet would have to be added to the manifest:
In the previous snippet FontToDownload is a query that will help the font from the Google Fonts Open Source
collection.
Before passing the FontRequest to the FontContractCompat.RequestFont method, there are two objects that must be
created:
FontsContractCompat.FontRequestCallback – This is an abstract class which must be extended. It is a callback that
will be invoked when RequestFont is finished. A Xamarin.Android app must subclass
FontsContractCompat.FontRequestCallback and override the OnTypefaceRequestFailed and OnTypefaceRetrieved ,
providing the actions to be taken when the download fails or succeeds respectively.
Handler – This is a Handler which will be used by RequestFont to download the font on a thread, if necessary.
Fonts should not be downloaded on the UI thread.
This snippet is an example of a C# class that will asynchronously download a font from Google Fonts Open Source
collection. It implements the FontRequestCallback interface, and raises a C# event when FontRequest has finished.
public class FontDownloadHelper : FontsContractCompat.FontRequestCallback
{
// A very simple font query; replace as necessary
public static readonly String FontToDownload = "Courgette";
Handler GetHandlerThreadHandler()
{
if (Handler == null)
{
HandlerThread handlerThread = new HandlerThread("fonts");
handlerThread.Start();
Handler = new Handler(handlerThread.Looper);
}
return Handler;
}
}
To use this helper, a new FontDownloadHelper is created, and an event handler is assigned:
var fontHelper = new FontDownloadHelper();
Summary
This guide discussed the new APIs in Android 8.0 to support downloadable fonts and fonts as resources. It
discussed how to embed existing fonts in an APK and to use them in a layout. It also discussed how Android 8.0
supports downloading fonts from a font provider, either programmatically or by declaring the font meta-data in
resource files.
Related Links
fontFamily
FontConfig
FontRequest
FontsContractCompat
Resources.GetFont
Typeface
Android Support Library 26 NuGet
Using Fonts in Android
CSS font weight specification
Google Fonts Open Source collection
Source Sans Pro
Activity Lifecycle
4/12/2018 • 17 minutes to read • Edit Online
Activities are a fundamental building block of Android applications and they can exist in a number of different
states. The activity lifecycle begins with instantiation and ends with destruction, and includes many states in
between. When an activity changes state, the appropriate lifecycle event method is called, notifying the activity of
the impending state change and allowing it to execute code to adapt to that change. This article examines the
lifecycle of activities and explains the responsibility that an activity has during each of these state changes to be
part of a well-behaved, reliable application.
Activity Lifecycle
The Android activity lifecycle comprises a collection of methods exposed within the Activity class that provide the
developer with a resource management framework. This framework allows developers to meet the unique state
management requirements of each activity within an application and properly handle resource management.
Activity States
The Android OS arbitrates Activities based on their state. This helps Android identify activities that are no longer
in use, allowing the OS to reclaim memory and resources. The following diagram illustrates the states an Activity
can go through during its lifetime:
These states can be broken into 4 main groups as follows:
1. Active or Running – Activities are considered active or running if they are in the foreground, also known as
the top of the activity stack. This is considered the highest priority activity in Android, and as such will only
be killed by the OS in extreme situations, such as if the activity tries to use more memory than is available
on the device as this could cause the UI to become unresponsive.
2. Paused – When the device goes to sleep, or an activity is still visible but partially hidden by a new, non-
full-sized or transparent activity, the activity is considered paused. Paused activities are still alive, that is,
they maintain all state and member information, and remain attached to the window manager. This is
considered to be the second highest priority activity in Android and, as such, will only be killed by the OS if
killing this activity will satisfy the resource requirements needed to keep the Active/Running Activity stable
and responsive.
3. Stopped/Backgrounded – Activities that are completely obscured by another activity are considered
stopped or in the background. Stopped activities still try to retain their state and member information for
as long as possible, but stopped activities are considered to be the lowest priority of the three states and,
as such, the OS will kill activities in this state first to satisfy the resource requirements of higher priority
activities.
4. Restarted – It is possible for an activity that is anywhere from paused to stopped in the lifecycle to be
removed from memory by Android. If the user navigates back to the activity it must be restarted, restored
to its previously saved state, and then displayed to the user.
Activity Re -Creation in Response to Configuration Changes
To make matters more complicated, Android throws one more wrench in the mix called Configuration Changes.
Configuration changes are rapid activity destruction/re-creation cycles that occur when the configuration of an
activity changes, such as when the device is rotated (and the activity needs to get re-built in landscape or portrait
mode), when the keyboard is displayed (and the activity is presented with an opportunity to resize itself ), or when
the device is placed in a dock, among others.
Configuration changes still cause the same Activity State changes that would occur during stopping and
restarting an activity. However, in order to make sure that an application feels responsive and performs well
during configuration changes, it's important that they be handled as quickly as possible. Because of this, Android
has a specific API that can be used to persist state during configuration changes. We'll cover this later in the
Managing State Throughout the Lifecycle section.
Activity Lifecycle Methods
The Android SDK and, by extension, the Xamarin.Android framework provide a powerful model for managing
the state of activities within an application. When an activity's state is changing, the activity is notified by the OS,
which calls specific methods on that activity. The following diagram illustrates these methods in relationship to
the Activity Lifecycle:
As a developer, you can handle state changes by overriding these methods within an activity. It's important to
note, however, that all lifecycle methods are called on the UI thread and will block the OS from performing the
next piece of UI work, such as hiding the current activity, displaying a new activity, etc. As such, code in these
methods should be as brief as possible to make an application feel well performing. Any long-running tasks
should be executed on a background thread.
Let's examine each of these lifecycle methods and their use:
OnCreate
OnCreate is the first method to be called when an activity is created. OnCreate is always overridden to perform
any startup initializations that may be required by an Activity such as:
Creating views
Initializing variables
Binding static data to lists
OnCreate takes a Bundle parameter, which is a dictionary for storing and passing state information and objects
between activities If the bundle is not null, this indicates the activity is restarting and it should restore its state
from the previous instance. The following code illustrates how to retrieve values from the bundle:
string intentString;
bool intentBool;
if (bundle != null)
{
intentString = bundle.GetString("myString");
intentBool = bundle.GetBoolean("myBool");
}
if (_camera==null)
{
// Do camera initializations here
}
}
OnResume is important because any operation that is done in OnPause should be un-done in OnResume , since it's
the only lifecycle method that is guaranteed to execute after OnPause when bringing the activity back to life.
OnPause
OnPause is called when the system is about to put the activity into the background or when the activity becomes
partially obscured. Activities should override this method if they need to:
Commit unsaved changes to persistent data
Destroy or clean up other objects consuming resources
Ramp down frame rates and pausing animations
Unregister external event handlers or notification handlers (i.e. those that are tied to a service). This must
be done to prevent Activity memory leaks.
Likewise, if the Activity has displayed any dialogs or alerts, they must be cleaned up with the .Dismiss()
method.
As an example, the following code snippet will release the camera, as the Activity cannot make use of it while
paused:
There are two possible lifecycle methods that will be called after OnPause :
1. OnResume will be called if the Activity is to be returned to the foreground.
2. OnStop will be called if the Activity is being placed in the background.
OnStop
OnStop is called when the activity is no longer visible to the user. This happens when one of the following occurs:
A new activity is being started and is covering up this activity.
An existing activity is being brought to the foreground.
The activity is being destroyed.
OnStop may not always be called in low -memory situations, such as when Android is starved for resources and
cannot properly background the Activity. For this reason, it is best not to rely on OnStop getting called when
preparing an Activity for destruction. The next lifecycle methods that may be called after this one will be
OnDestroy if the Activity is going away, or OnRestart if the Activity is coming back to interact with the user.
OnDestroy
OnDestroy is the final method that is called on an Activity instance before it's destroyed and completely removed
from memory. In extreme situations Android may kill the application process that is hosting the Activity, which
will result in OnDestroy not being invoked. Most Activities will not implement this method because most clean up
and shut down has been done in the OnPause and OnStop methods. The OnDestroy method is typically
overridden to clean up long running resources that might leak resources. An example of this might be
background threads that were started in OnCreate .
There will be no lifecycle methods called after the Activity has been destroyed.
OnRestart
OnRestart is called after your activity has been stopped, prior to it being started again. A good example of this
would be when the user presses the home button while on an activity in the application. When this happens
OnPause and then OnStop methods are called, and the Activity is moved to the background but is not destroyed.
If the user were then to restore the application by using the task manager or a similar application, Android will
call the OnRestart method of the activity.
There are no general guidelines for what kind of logic should be implemented in OnRestart . This is because
OnStart is always invoked regardless of whether the Activity is being created or being restarted, so any
resources required by the Activity should be initialized in OnStart , rather than OnRestart .
The next lifecycle method called after OnRestart will be OnStart .
Back vs. Home
Many Android devices have two distinct buttons: a "Back" button and a "Home" button. An example of this can be
seen in the following screenshot of Android 4.0.3:
There is a subtle difference between the two buttons, even though they appear to have the same effect of putting
an application in the background. When a user clicks the Back button, they are telling Android that they are done
with the activity. Android will destroy the Activity. In contrast, when the user clicks the Home button the activity is
merely placed into the background – Android will not kill the activity.
int c;
this.SetContentView (Resource.Layout.SimpleStateView);
if (bundle != null) {
c = bundle.GetInt ("counter", -1);
} else {
c = -1;
}
The code above increments an integer named c when a button named incrementCounter is clicked, displaying
the result in a TextView named output . When a configuration change happens - for example, when the device is
rotated - the above code would lose the value of c because the bundle would be null , as shown in the figure
below:
To preserve the value of c in this example, the Activity can override OnSaveInstanceState , saving the value in the
bundle as shown below:
Now when the device is rotated to a new orientation, the integer is saved in the bundle and is retrieved with the
line:
NOTE
It is important to always call the base implementation of OnSaveInstanceState so that the state of the view hierarchy can
also be saved.
Vi e w St a t e
Overriding OnSaveInstanceState is an appropriate mechanism for saving transient data in an Activity across
orientation changes, such as the counter in the above example. However, the default implementation of
OnSaveInstanceState will take care of saving transient data in the UI for every view, so long as each view has an
ID assigned. For example, say an application has an EditText element defined in XML as follows:
<EditText android:id="@+id/myText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
Since the EditText control has an id assigned, when the user enters some data and rotates the device, the data
is still displayed, as shown below:
OnRestoreInstanceState
OnRestoreInstanceState will be called after OnStart . It provides an activity the opportunity to restore any state
that was previously saved to a Bundle during the previous OnSaveInstanceState . This is the same bundle that is
provided to OnCreate , however.
The following code demonstrates how state can be restored in OnRestoreInstanceState :
This method exists to provide some flexibility around when state should be restored. Sometimes it is more
appropriate to wait until all initializations are done before restoring instance state. Additionally, a subclass of an
existing Activity may only want to restore certain values from the instance state. In many cases, it's not necessary
to override OnRestoreInstanceState , since most activities can restore state using the bundle provided to
OnCreate .
For an example of saving state using a Bundle , refer to the Walkthrough - Saving the Activity state.
Bundle Limitations
Although OnSaveInstanceState makes it easy to save transient data, it has some limitations:
It is not called in all cases. For example, pressing Home or Back to exit an Activity will not result in
OnSaveInstanceState being called.
The bundle passed into OnSaveInstanceState is not designed for large objects, such as images. In the case
of large objects, saving the object from OnRetainNonConfigurationInstance is preferable, as discussed
below.
Data saved by using the bundle is serialized, which can lead to delays.
Bundle state is useful for simple data that doesn't use much memory, whereas non-configuration instance data is
useful for more complex data, or data that is expensive to retrieve, such as from a web service call or a
complicated database query. Non-configuration instance data gets saved in an object as needed. The next section
introduces OnRetainNonConfigurationInstance as a way of preserving more complex data types through
configuration changes.
Persisting Complex Data
In addition to persisting data in the bundle, Android also supports saving data by overriding
OnRetainNonConfigurationInstance and returning an instance of a Java.Lang.Object that contains the data to
persist. There are two primary benefits of using OnRetainNonConfigurationInstance to save state:
The object returned from OnRetainNonConfigurationInstance performs well with larger, more complex data
types because memory retains this object.
The OnRetainNonConfigurationInstance method is called on demand, and only when needed. This is more
economical than using a manual cache.
Using OnRetainNonConfigurationInstance is suitable for scenarios where it is expensive to retrieve the data
multiple times, such as in web service calls. For example, consider the following code that searches Twitter:
var results = (from result in (JsonArray)j ["results"] let jResult = result as JsonObject select jResult
["text"].ToString ()).ToArray ();
This code retrieves results from the web formatted as JSON, parses them, and then presents the results in a list,
as shown in the following screenshot:
When a configuration change occurs - for example, when a device is rotated - the code repeats the process. To
reuse the originally retrieved results and not cause needless, redundant network calls, we can use
OnRetainNonconfigurationInstance to save the results, as shown below:
if (tweetsWrapper != null) {
PopulateTweetList (tweetsWrapper.Tweets);
} else {
SearchTwitter ("xamarin");
}
...
Now when the device is rotated, the original results are retrieved from the LastNonConfiguartionInstance
property. In this example, the results consist of a string[] containing tweets. Since
OnRetainNonConfigurationInstance requires that a Java.Lang.Object be returned, the string[] is wrapped in a
class that subclasses Java.Lang.Object , as shown below:
For example, attempting to use a TextView as the object returned from OnRetainNonConfigurationInstance will
leak the Activity, as illustrated by the code below:
TextView _textView;
if(tv != null) {
_textView = tv;
var parent = _textView.Parent as FrameLayout;
parent.RemoveView(_textView);
} else {
_textView = new TextView (this);
_textView.Text = "This will leak.";
}
SetContentView (_textView);
}
In this section, we learned how to preserve simple state data with the Bundle , and persist more complex data
types with OnRetainNonConfigurationInstance .
Summary
The Android activity lifecycle provides a powerful framework for state management of activities within an
application but it can be tricky to understand and implement. This chapter introduced the different states that an
activity may go through during its lifetime, as well as the lifecycle methods that are associated with those states.
Next, guidance was provided as to what kind of logic should be performed in each of these methods.
Related Links
Handling Rotation
Android Activity
Walkthrough - Saving the Activity state
4/12/2018 • 4 minutes to read • Edit Online
We have covered the theory behind saving state in the Activity Lifecycle guide; now, let's walk through an example.
When we click the Start Activity B button, we see Activity A pause and stop while Activity B goes through its
state changes:
[ActivityLifecycle.MainActivity] Activity A - OnPause
[ActivityLifecycle.SecondActivity] Activity B - OnCreate
[ActivityLifecycle.SecondActivity] Activity B - OnStart
[ActivityLifecycle.SecondActivity] Activity B - OnResume
[ActivityLifecycle.MainActivity] Activity A - OnStop
When we click the Back button, Activity B is destroyed and Activity A is resumed:
int _counter = 0;
Next, let's edit the Resource/layout/Main.axml layout file and add a new clickButton that displays the number
of times the user has clicked the button. The resulting Main.axml should resemble the following:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<Button
android:id="@+id/myButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/mybutton_text" />
<Button
android:id="@+id/clickButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/counterbutton_text" />
</LinearLayout>
Let's add the following code to the end of the OnCreate method in MainActivity – this code handles click events
from the clickButton :
When we build and run the app again, a new button appears that increments and displays the value of _counter
on each click:
But when we rotate the device to landscape mode, this count is lost:
Examining the application output, we see that Activity A was paused, stopped, destroyed, recreated, restarted, then
resumed during the rotation from portrait to landscape mode:
Because Activity A is destroyed and recreated again when the device is rotated, its instance state is lost. Next, we
will add code to save and restore the instance state.
Adding Code to Preserve Instance State
Let's add a method to MainActivity to save the instance state. Before Activity A is destroyed, Android
automatically calls OnSaveInstanceState and passes in a Bundle that we can use to store our instance state. Let's
use it to save our click count as an integer value:
When Activity A is recreated and resumed, Android passes this Bundle back into our OnCreate method. Let's add
code to OnCreate to restore the _counter value from the passed-in Bundle . Add the following code just before
the line where clickbutton is defined:
if (bundle != null)
{
_counter = bundle.GetInt ("click_count", 0);
Log.Debug(GetType().FullName, "Activity A - Recovered instance state");
}
Build and run the app again, then click the second button a few times. When we rotate the device to landscape
mode, the count is preserved!
Before the OnStop method was called, our new OnSaveInstanceState method was called to save the _counter
value in a Bundle . Android passed this Bundle back to us when it called our OnCreate method, and we were able
to used it to restore the _counter value to where we left off.
Summary
In this walkthough, we have used our knowledge of the Activity Lifecycle to preserve state data.
Related Links
ActivityLifecycle (sample)
Activity Lifecycle
Android Activity
Creating Android Services
6/7/2018 • 9 minutes to read • Edit Online
This guide discusses Xamarin.Android services, which are Android components that allow work to be done without
an active user interface. Services are very commonly used for tasks that are performed in the background, such as
time consuming calculations, downloading files, playing music, and so on. It explains the different scenarios that
services are suited for and shows how to implement them both for performing long -running background tasks as
well as for providing an interface for remote procedure calls.
This is a potential memory leak – the thread created by the first instance of the Activity will still be running. If the
thread has a reference to the first instance of the Activity, this will prevent Android from garbage collecting the
object. However, the second instance of the Activity is still created (which in turn might create a new thread).
Rotating the device several times in rapid succession may exhaust all the RAM and force Android to terminate the
entire application to reclaim memory.
As a rule of thumb, if the work to be performed should outlive an Activity, then a service should be created to
perform that work. However, if the work is only applicable in the context of an Activity, then creating a thread to
perform the work might be more appropriate. For example, creating a thumbnail for a photo that was just added
to a photo gallery app should probably occur in a service. However, a thread might be more appropriate to play
some music that should only be heard while an Activity is in the foreground.
Background work can be broken down into two broad classifications:
1. Long Running Task – This is work that is ongoing until explicitly stopped. An example of a long running task
is an app that streams music or that must monitor data collected from a sensor. These tasks must run even
though the application has no visible user interface.
2. Periodic Tasks – (sometimes referred to as a job) A periodic task is one that is of relatively short in duration
(several seconds) and is run on a schedule (i.e. once a day for a week or perhaps just once in the next 60
seconds). An example of this is downloading a file from the internet or generating a thumbnail for an image.
There are four different types of Android services:
Bound Service – A bound service is a service that has some other component (typically an Activity) bound
to it. A bound service provides an interface that allows the bound component and the service to interact
with each other. Once there are no more clients bound to the service, Android will shut the service down.
IntentService – An IntentService is a specialized subclass of the Service class that simplifies service
creation and usage. An IntentService is meant to handle individual autonomous calls. Unlike a service,
which can concurrently handle multiple calls, an IntentService is more like a work queue processor – work
is queued up and an IntentService processes each job one at a time on a single worker thread. Typically,
an IntentService is not bound to an Activity or a Fragment.
Started Service – A started service is a service that has been started by some other Android component
(such as an Activity) and is run continously in the background until something explicitly tells the service to
stop. Unlike a bound service, a started service does not have any clients directly bound to it. For this reason,
it is important to design started services so that they may be gracefully restarted as necessary.
Hybrid Service – A hybrid service is a service that has the characteristics of a started service and a bound
service. A hybrid service can be started by when a component binds to it or it may be started by some
event. A client component may or may not be bound to the hybrid service. A hybrid service will keep
running until it is explicitly told to stop, or until there are no more clients bound to it.
Which type of service to use is very dependent on application requirements. As a rule of thumb, an IntentService
or a bound service are sufficient for most tasks that an Android application must perform, so preference should be
given to one of those two types of services. An IntentService is a good choice for "one-shot" tasks, such as
downloading a file, while a bound service would be suitable when frequent interactions with an Activity/Fragment
is required.
While most services run in the background, there is a special sub-category known as a foreground service. This is
a service that is given a higher priority (compared to a normal service) to perform some work for the user (such as
playing music).
It is also possible to run a service in it's own process on the same device, this is sometimes referred to as a remote
service or as an out-of-process service. This does require more effort to create, but can be useful for when an
application needs to share functionality with other applications, and can, in some cases, improve the user
experience of an application.
Background Execution Limits in Android 8.0
Starting in Android 8.0 (API level 26), an Android application no longer have the ability to run freely in the
background. When in the foreground, an app can start and run services without restriction. When an application
moves into the background, Android will grant the app a certain amount of time to start and use services. Once
that time has elapsed, the app can no longer start any services and any services that were started will be
terminated. At this point is is not possible for the app to perform any work. Android considers an application to be
in the foreground if one of the following conditions are met:
There is a visible activity (either started or paused).
The app has started a foreground service.
Another app is in the foreground and is using components from an app that would be otherwise in the
background. An example of this is if Application A, which is in the foreground, is bound to a service provided
by Application B. Application B would then also be considered in the foreground, and not terminated by
Android for being in the background.
There are some situations where, even though an app is in the background, Android will wake up the app and
relax these restrictions for a few minutes, allowing the app to perform some work:
A high priority Firebase Cloud Message is received by the app.
The app receives a broadcast, such as
The application receives an executes a PendingIntent in response to a Notification.
Existing Xamarin.Android applications may have to change how they perform background work to avoid any
issues that might arise on Android 8.0. Here are some practical alterantives to an Android service:
Schedule work to run in the background using the Android Job Scheduler or the Firebase Job
Dispatcher – These two libraries provide a framework for applications to segregate background work in to
jobs, a discrete unit of work. Apps can then schedule the job with the operating system along with some criteria
about when the job can run.
Start the service in the foreground – a foreground service is useful for when the app must perform some
task in the background and the user may need to periodically interact with that task. The foreground service
will display a persistent notification so that the user is aware that the app is running a background task and also
provides a way to monitor or interact with the task. An example of this would be a podcasting app that is
playing back a podcast to the user or perhaps downloading a podcast episode so that it can be enjoyed later.
Use a high priority Firebase Cloud Message (FCM ) – When Android receives a high priority FCM for an
app, it will allow that app to run services in the background for a short period of time. This would be a good
alternative to having a background service that polls an app in the background.
Defer work for when the app comes into the foreground – If none of the previous solutions are viable,
then apps must develop their own way to pause and resume work when the app comes to the foreground.
Related Links
Android Oreo Background Execution Limits
Creating a Service
5/7/2018 • 4 minutes to read • Edit Online
[Service]
public class DemoService : Service
{
// Magical code that makes the service do wonderful things.
}
At compile time, Xamarin.Android will register the service by injecting the following XML element into
AndroidManifest.xml (notice that Xamarin.Android generated a random name for the service):
It is possible to share a service with other Android applications by exporting it. This is accomplished by setting the
Exported property on the ServiceAttribute . When exporting a service, the ServiceAttribute.Name property
should also be set to provide a meaningful public name for the service. This snippet demonstrates how to export
and name a service:
[Service(Exported=true, Name="com.xamarin.example.DemoService")]
public class DemoService : Service
{
// Magical code that makes the service do wonderful things.
}
The AndroidManifest.xml element for this service will then look something like:
Services have their own lifecycle with callback methods that are invoked as the service is created. Exactly which
methods are invoked depends on the type of service. A started service must implement different lifecycle methods
than a bound service, while a hybrid service must implement the callback methods for both a started service and a
bound service. These methods are all members of the Service class; how the service is started will determine
what lifecycle methods will be invoked. These lifecycle methods will be discussed in more detail later.
By default, a service will start in the same process as an Android application. It is possible to start a service in its
own process by setting the ServiceAttribute.IsolatedProcess property to true:
[Service(IsolatedProcess=true)]
public class DemoService : Service
{
// Magical code that makes the service do wonderful things, in it's own process!
}
The next step is to examine how to start a service and then move on to examine how to implement the three
different types of services.
NOTE
A service runs on the UI thread, so if any work is to be performed which blocks the UI, the service must use threads to
perform the work.
Starting A Service
The most basic way to start a service in Android is to dispatch an Intent which contains meta-data to help identify
which service should be started. There are two different styles of Intents that can be used to start a service:
Explicit Intent – An explicit Intent will identify exactly what service should be used to complete a given
action. An explicit Intent can be thought of as a letter that has a specific address; Android will route the intent
to the service that is explicitly identified. This snippet is one example of using an explicit Intent to start a
service called DownloadService :
Implicit Intent – This type of Intent loosely identifies the of action that the user wishes to perform, but the
exact service to complete that action is unknown. An implicit Intent can be thought of as a letter that is
addressed "To Whom It May Concern...". Android will examine the contents of the Intent, and determine if
there is an existing service which matches the intent.
An intent filter is used to help match the implicit intent with a registered service. An intent filter is an XML
element that is added to AndroidManifest.xml which contains the necessary meta-data to help match a
Service with an implicit intent.
If Android has more than one possible match for an implicit intent, then it may ask the user to select the
component to handle the action:
IMPORTANT
Starting in Android 5.0 (AP level 21) an implicit intent cannot be used to start a service.
Where possible, applications should use explicit Intents to start a service. An implicit Intent does not ask for a
specific service to start – it is a request for some service installed on the device to handle the request. This
ambiguous request can result in the wrong service handling the request or another app needlessly starting (which
increases the pressure for resources on the device).
How the Intent is dispatched depends on the type of service and will be discussed in more detail later in the guides
specific to each type of service.
Creating an Intent Filter for Implicit Intents
To associate a service with a implicit Intent, an Android app must provide some meta-data to identify the
capabilities of the service. This meta-data is provided by intent filters. Intent filters contain some information, such
as an action or a type of data, that must be present in an Intent to start a service. In Xamarin.Android, the intent
filter is registered in AndroidManifest.xml by decorating a service with the IntentFilterAttribute . For example,
the following code adds an intent filter with an associated action of com.xamarin.DemoService :
[Service]
[IntentFilter(new String[]{"com.xamarin.DemoService"})]
public class DemoService : Service
{
}
This results in an entry being included in the AndroidManifest.xml file – an entry that is packaged with the
application in a way analogous to the following example:
<service android:name="demoservice.DemoService">
<intent-filter>
<action android:name="com.xamarin.DemoService" />
</intent-filter>
</service>
With the basics of a Xamarin.Android service out of the way, let's examine the the different subtypes of services in
more detail.
Related Links
Android.App.Service
Android.App.ServiceAttribute
Android.App.Intent
Android.App.IntentFilterAttribute
Bound Services in Xamarin.Android
5/7/2018 • 11 minutes to read • Edit Online
Bound services are Android services that provide a client-server interface that a client (such as an Android Activity )
can interact with. This guide will discuss the key components involved with creating a bound service and how to
use it in a Xamarin.Android application.
namespace BoundServiceDemo
{
[Service(Name="com.xamarin.ServicesDemo1")]
public class TimestampService : Service, IGetTimestamp
{
static readonly string TAG = typeof(TimestampService).FullName;
IGetTimestamp timestamper;
/// <summary>
/// This method will return a formatted timestamp to the client.
/// </summary>
/// <returns>A string that details what time the service started and how long it has been running.
</returns>
public string GetFormattedTimestamp()
{
return timestamper?.GetFormattedTimestamp();
}
}
}
In the sample, the OnCreate method initializes an object that holds the logic for retrieving and formatting a
timestamp that would be requested by a client. When the first client tries to bind to the service, Android will invoke
the OnBind method. This service will instantiate a TimestampServiceBinder object that will allow the clients to
access this instance of the running service. The TimestampServiceBinder class is discussed in the next section.
Implementing IBinder
As mentioned, an IBinder object provides the communication channel between a client and a service. Android
applications should not implement the IBinder interface, the Android.OS.Binder should be extended. The Binder
class provides much of the necessary infrastructure which is necessary marshal the binder object from the service
(which may be running in a separate process) to the client. In most cases, the Binder subclass is only a few lines of
code and wraps a reference to the service. In this example, TimestampBinder has a property that exposes the
TimestampService to the client:
This Binder makes it possible to invoke the public methods on the service; for example:
Once Binder has been extended, it is necessary to implement IServiceConnection to connect everything together.
Creating the Service Connection
The IServiceConnection will present|introduce|expose|connect the Binder object to the client. In addition to
implementing the IServiceConnection interface, the class must extend Java.Lang.Object . The service connection
should also provide some way that the client can access the Binder (and therefore communicate with the bound
service).
This code is from the accompanying sample project is one possible way to implement IServiceConnection :
using Android.Util;
using Android.OS;
using Android.Content;
namespace BoundServiceDemo
{
public class TimestampServiceConnection : Java.Lang.Object, IServiceConnection, IGetTimestamp
{
static readonly string TAG = typeof(TimestampServiceConnection).FullName;
MainActivity mainActivity;
public TimestampServiceConnection(MainActivity activity)
{
IsConnected = false;
Binder = null;
mainActivity = activity;
}
if (IsConnected)
{
message = message + " bound to service " + name.ClassName;
mainActivity.UpdateUiForBoundService();
}
else
{
message = message + " not bound to service " + name.ClassName;
mainActivity.UpdateUiForUnboundService();
}
Log.Info(TAG, message);
mainActivity.timestampMessageTextView.Text = message;
return Binder?.GetFormattedTimestamp();
}
}
}
As a part of the binding process, Android will invoke the OnServiceConnected method, providing the name of the
service that is being bound and the binder that holds a reference to the service itself. In this example, the service
connection has two properties, one that holds a reference to the Binder and a boolean flag for if the client is
connected to the service or not.
The OnServiceDisconnected method is only invoked when the connection between a client and a service is
unexpectedly lost or broken. This method allows the client a chance to respond to the interruption in service.
if (serviceConnection == null)
{
this.serviceConnection = new TimestampServiceConnection(this);
}
IMPORTANT
Starting with Android 5.0 (API level 21) it is only possible to bind to a service with an explicit intent.
This particular example allow an activity to invoke methods on the service itself:
// In this example the Activity is only talking to a friend, i.e. the IGetTimestamp interface provided by the
Binder.
string currentTimestamp = serviceConnection.Binder.GetFormattedTimestamp()
Related Links
Android.App.Service
Android.Content.Bind
Android.Content.Context
Android.Content.IServiceConnection
Android.OS.Binder
Android.OS.IBinder
BoundServiceDemo (sample)
Intent Services in Xamarin.Android
4/12/2018 • 2 minutes to read • Edit Online
[Service]
public class DemoIntentService: IntentService
{
public DemoIntentService () : base("DemoIntentService")
{
}
Work is sent to an IntentService by instantiating an Intent and then calling the StartService method with that
Intent as a parameter. The Intent will be passed to the service as a parameter in the OnHandleIntent method. This
code snippet is an example of sending a work request to an Intent:
// This code might be called from within an Activity, for example in an event
// handler for a button click.
Intent downloadIntent = new Intent(this, typeof(DemoIntentService));
// This is just one example of passing some values to an IntentService via the Intent:
downloadIntent.Put
("file_to_download", "http://www.somewhere.com/file/to/download.zip");
StartService(downloadIntent);
The IntentService can extract the values from the Intent, as demonstrated in this code snippet:
Related Links
IntentService
StartService
Started Services with Xamarin.Android
4/12/2018 • 5 minutes to read • Edit Online
The first parameter is an Intent object containing the meta-data about the work to perform. The second
parameter contains a StartCommandFlags value that provides some information about the method call. This
parameter has one of two possible values:
StartCommandFlag.Redelivery – This means that the Intent is a re-delivery of a previous Intent . This value is
provided when the service had returned StartCommandResult.RedeliverIntent but was stopped before it could be
properly shut down.
StartCommandFlag.Retry - This value is received when a previous OnStartCommand call failed and Android is
trying to start the service again with the same intent as the previous failed attempt.
Finally, the third parameter is an integer value that is unique to the application that identifies the request. It is
possible that multiple callers may invoke the same service object. This value is used to associate a request to stop a
service with a given request to start a service. It will be discussed in more detail in the section Stopping the Service.
The value StartCommandResult is returned by the service as a suggestion to Android on what to do if the service is
killed due to resource constraints. There are three possible values for StartCommandResult :
StartCommandResult.NotSticky – This value tells Android that it is not necessary to restart the service that it
has killed. As an example of this, consider a service that generates thumbnails for a gallery in an app. If the
service is killed, it isn't crucial to recreate the thumbnail immediately – the thumbnail can be recreated the next
time the app is run.
StartCommandResult.Sticky – This tells Android to restart the Service, but not to deliver the last Intent that
started the Service. If there are no pending Intents to handle, then a null will be provided for the Intent
parameter. An example of this might be a music player app; the service will restart ready to play music, but it
will play the last song.
StartCommandResult.RedeliverIntent – This value is will tell Android to restart the service and re-deliver the
last Intent . An example of this is a service that downloads a data file for an app. If the service is killed, the data
file still needs to be downloaded. By returning StartCommandResult.RedeliverIntent , when Android restarts the
service it will also provide the Intent (which holds the URL of the file to download) to the service. This will
enable the download to either restart or resume (depending on the exact implementation of the code).
There is a fourth value for StartCommandResult – StartCommandResult.ContinuationMask . This value is returned by
OnStartCommand and it describes how Android will continue the service it has killed. This value isn't typically used to
start a service.
The key lifecycle events of a started service are shown in this diagram:
Stopping the Service
A started service will keep running indefinitely; Android will keep the service running as long as there are sufficient
system resources. Either the client must stop the service, or the service may stop itself when it is done its work.
There are two ways to stop a service:
Android.Content.Context.StopService() – A client (such as an Activity) can request a service stop by
calling the StopService method:
Related Links
StartedServicesDemo (sample)
Android.App.Service
Android.App.StartCommandFlags
Android.App.StartCommandResult
Android.Content.BroadcastReceiver
Android.Content.Intent
Android.OS.Handler
Android.Widget.Toast
Status Bar Icons
Foreground Services
7/11/2018 • 3 minutes to read • Edit Online
A foreground service is a special type of a bound service or a started service. Occasionally services will perform
tasks that users must be actively aware of, these services are known as foreground services. An example of a
foreground service is an app that is providing the user with directions while driving or walking. Even if the app is in
the background, it is still important that the service has sufficient resources to work properly and that the user has
a quick and handy way to access the app. For an Android app, this means that a foreground service should receive
higher priority than a "regular" service and a foreground service must provide a Notification that Android will
display as long as the service is running.
To start a foreground service, the app must dispatch an Intent that tells Android to start the service. Then the
service must register itself as a foreground service with Android. Apps that are running on Android 8.0 (or higher)
should use the Context.StartForegroundService method to start the service, while apps that are running on devices
with an older version of Android should use Context.StartService
This C# extension method is an example of how to start a foreground service. On Android 8.0 and higher it will use
the StartForegroundService method, otherwise the older StartService method will be used.
public static void StartForegroundServiceComapt<T>(this Context context, Bundle args = null) where T : Service
{
var intent = new Intent(context, typeof(T));
if (args != null)
{
intent.PutExtras(args);
}
The previous notification will display a status bar notification that that is similar to the following:
This screenshot shows the expanded notification in the notification tray with two actions that allow the user to
control the service:
More information about notifications is available in the Local Notifications section of the Android Notifications
guide.
StopForeground(true);
If the service is halted with a call to StopSelf or StopService , the status bar notification will be removed.
Related Links
Android.App.Service
Android.App.Service.StartForeground
Local Notifications
ForegroundServiceDemo (sample)
Running Android Services in Remote Processes
4/12/2018 • 26 minutes to read • Edit Online
Generally, all components in an Android application will run in the same process. Android services are a notable
exception to this in that they can be configured to run in their own processes and shared with other applications,
including those from other Android developers. This guide will discuss how to create and use an Android remote
service using Xamarin.
This guide will discuss the details of implementing an out-of-process service. It will discuss how to implement a
service that is meant to run in its own process and how a client may communicate with that service using the
Messenger framework. It will also briefly discuss two-way communication: the client sending a message to a
service and the service sending a message back to the client. Because services can be shared between different
applications, this guide will also discuss one technique for limiting client access to the service by using Android
permissions.
IMPORTANT
Bugzilla 51940 - Services with isolated processes and custom Application class fail to resolve overloads properly reports that
a Xamarin.Android service will not start up properly when the IsolatedProcess is set to true . This guide is provided for a
reference. A Xamarin.Android application should still be able to communicate with an out-of-process service that is written in
Java.
Requirements
This guide assumes familiarity with creating services.
Although it is possible to use implicit intents with apps that target older Android APIs, this guide will focus
exclusively on the use of explicit intents. Apps targeting Android 5.0 (API level 21) or higher must use an explicit
intent to bind with a service; this is the technique that will be demonstrated in this guide..
[Service(Name = "com.xamarin.TimestampService",
Process=":timestampservice_process",
Exported=true)]
Global Process – A service that is run in a global process is accessible to all applications running on the
device. A global process must be a fully qualified class name that starts with a lower case character. (Unless
steps are taken to secure the service, other applications may bind and interact with it. Securing the service
against unauthorized use will be discussed later in this guide.)
[Service(Name = "com.xamarin.TimestampService",
Process="com.xamarin.xample.messengerservice.timestampservice_process",
Exported=true)]
Isolated Process – An isolated process is a process that runs in its own sandbox, isolated from the rest of
the system and with no special permissions of its own. To run a service in an isolated process, the
IsolatedProcess property of the ServiceAttribute is set to true as shown in this code snippet:
[Service(Name = "com.xamarin.TimestampService",
IsolatedProcess= true,
Process="com.xamarin.xample.messengerservice.timestampservice_process",
Exported=true)]
IMPORTANT
See Bugzilla 51940 - Services with isolated processes and custom Application class fail to resolve overloads properly
An isolated service is a simple way to secure an application and the device against untrusted code. For example, an
app may download and execute a script from a website. In this case, performing this in an isolated process provides
an additional layer of security against untrusted code compromising the Android device.
IMPORTANT
Once a service has been exported, the name of the service should not change. Changing the name of the service may break
other applications that are using the service.
To see the effect that the Process property has, the following screenshot shows a service running in its own
private process:
switch (messageType)
{
case Constants.SAY_HELLO_TO_TIMESTAMP_SERVICE:
// The client as sent a simple Hello, say in the Android Log.
break;
case Constants.GET_UTC_TIMESTAMP:
// Call methods on the service to retrive a timestamp message.
break;
default:
Log.Warn(TAG, $"Unknown messageType, ignoring the value {messageType}.");
base.HandleMessage(msg);
break;
}
}
}
It is also possible to package parameters for the service in the Message . This will be discussed later in this guide.
The next topic to consider is creating the Messenger object to process the incoming Message s.
Instantiating the Messenger
As previously discussed, deserializing the Message object and invoking Handler.HandleMessage is the responsibilty
of the Messenger object. The Messenger class also provides an IBinder object that the client will use to send
messages to the service.
When the service starts, it will instantiate the Messenger and inject the Handler . A good place to perform this
initialization is on the OnCreate method of the service. This code snippet is one example of a service that initializes
its own Handler and Messenger :
At this point, the final step is for the Service to override OnBind .
Implementing Service.OnBind
All bound services, whether they run in their own process or not, must implement the OnBind method. The return
value of this method is some object that the client can use to interact with the service. Exactly what that object is
depends whether the service is a local service or a remote service. While a local service will return a custom
IBinder implementation, a remote service will return the IBinder that is encapsulated but the Messenger that
was created in the previous section:
public override IBinder OnBind(Intent intent)
{
Log.Debug(TAG, "OnBind");
return messenger.Binder;
}
Once these three steps are accomplished, the remote service can be considered complete.
// This is the package name of the APK, set in the Android manifest
const string REMOTE_SERVICE_COMPONENT_NAME = "com.xamarin.TimestampService";
// This is the name of the service, according the value of ServiceAttribute.Name
const string REMOTE_SERVICE_PACKAGE_NAME = "com.xamarin.xample.messengerservice";
// Provide the package name and the name of the service with a ComponentName object.
ComponentName cn = new ComponentName(REMOTE_SERVICE_PACKAGE_NAME, REMOTE_SERVICE_COMPONENT_NAME);
Intent serviceToStart = new Intent();
serviceToStart.SetComponent(cn);
When the service is bound, the IServiceConnection.OnServiceConnected method is invoked and provides an
IBinder to a client. However, the client will not directly use the IBinder . Instead, it will instantiate a Messenger
object from that IBinder . This is the Messenger that the client will use to interact with the remote service.
The following is an example of a very basic IServiceConnection implementation that demonstrates how a client
would handle connecting to and disconnecting from a service. Notice that the OnServiceConnected method receives
and IBinder , and the client creates a Messenger from that IBinder :
public class TimestampServiceConnection : Java.Lang.Object, IServiceConnection
{
static readonly string TAG = typeof(TimestampServiceConnection).FullName;
MainActivity mainActivity;
Messenger messenger;
if (IsConnected)
{
// things to do when the connection is successful. perhaps notify the client? enable UI features?
}
else
{
// things to do when the connection isn't successful.
}
}
// Things to do when the service disconnects. perhaps notify the client? disable UI features?
}
}
Once the service connection and the intent are created, it is possible for the client to call BindService and initiate
the binding process:
After the client has successfully bound to the service and the Messenger is available, it is possible for the client to
send Messages to the service.
There are several different forms of the Message.Obtain method. The previous example uses the
Message.Obtain(Handler h, Int32 what) . Because this is an asynchronous request to an out-of-process service; there
will be no response from the service, so the Handler is set to null . The second parameter, Int32 what , will be
stored in the .What property of the Message object. The .What property is used by code in the service process to
invoke methods on the service.
The Message class also exposes two additional properties that may be of use to the recipent: Arg1 and Arg2 .
These two properties are integer values that may have some special agreed upon values that have meaning
between the client and the service. For example, Arg1 may hold a customer ID and Arg2 may hold a purchase
order number for that customer. The Method.Obtain(Handler h, Int32 what, Int32 arg1, Int32 arg2) can be used to
set the two properties when the Message is created. Another way to populate these two values is to set the .Arg
and .Arg2 properties directly on the Message object after it has been created.
Passing Additional Values to the Service
It is possible to pass more complex data to the service by using a Bundle . In this case, extra values can be placed in
a Bundle and sent along with the Message by setting the .Data property property before sending.
messenger.Send(msg);
NOTE
In general, a Message should not have a payload larger than 1MB. The size limit may vary according the version of Android
and on any proprietary changes the vendor might have made to their implementation of the Android Open Source Project
(AOSP) that is bundled with the device.
This sample code demonstrates how the client will instantiate the Message and package a Messenger that the
service should use for its response:
try
{
serviceConnection.Messenger.Send(msg);
}
catch (RemoteException ex)
{
Log.Error(TAG, ex, "There was a problem sending the message.");
}
The service must make some changes to its own Handler to extract the Messenger and use that to send replies to
the client. This code snippet is an example of how the service's Handler would create a Message and send it back
to the client:
// This is the message that the service will send to the client.
Message responseMessage = Message.Obtain(null, Constants.RESPONSE_TO_SERVICE);
Bundle dataToReturn = new Bundle();
dataToReturn.PutString(Constants.RESPONSE_MESSAGE_KEY, "This is the result from the service.");
responseMessage.Data = dataToReturn;
// The msg object here is the message that was received by the service. The service will not instantiate a
client,
// It will use the client that is encapsulated by the message from the client.
Messenger clientMessenger = msg.ReplyTo;
if (clientMessenger!= null)
{
try
{
clientMessenger.Send(responseMessage);
}
catch (Exception ex)
{
Log.Error(TAG, ex, "There was a problem sending the message.");
}
}
Note that in the code samples above, the Messenger instance that is created by the client is not the same object that
is received by the service. These are two different Messenger objects running in two separate processes that
represent the communication channel.
[Service(Name = "com.xamarin.TimestampService",
Process="com.xamarin.TimestampService.timestampservice_process",
Permission="signature")]
public class TimestampService : Service
{
}
2. Create a custom permission – It is possible for the developer of the service to create a custom permission
for the service. This is best for when a developer wants to share their service with applications from other
developers. A custom permission requires a bit more effort to implement and will be covered below.
A simplified example of creating a custom normal permission will be described in the next section. For more
information about Android permissions, please consult Google's documentation for Best Practices & Security. For
more information about Android permissions, see the Permissions section of the Android documentation for the
application manifest for more information about Android permissions.
NOTE
In general, Google discourages the use of custom permissions as they may prove confusing to users.
<permission android:name="com.xamarin.xample.messengerservice.REQUEST_TIMESTAMP"
android:protectionLevel="signature"
android:label="@string/permission_label"
android:description="@string/permission_description"
/>
<application android:allowBackup="true"
android:icon="@mipmap/icon"
android:label="@string/app_name"
android:theme="@style/AppTheme">
</application>
</manifest>
Then, the AndroidManifest.xml of the client APK must explicitly request this new permission. This is done by
adding the users-permission attribute to the AndroidManifest.xml:
<application
android:allowBackup="true"
android:icon="@mipmap/icon"
android:label="@string/app_name"
android:theme="@style/AppTheme">
</application>
</manifest>
Related Links
Handler
Message
Messenger
ServiceAttribute
The Exported attribute
Services with isolated processes and custom Application class fail to resolve overloads properly
Processes and Threads
Android Manifest - Permissions
Security Tips
MessengerServiceDemo (sample)
Service Notifications
4/12/2018 • 2 minutes to read • Edit Online
This guide discusses how an Android service may use local notifications to dispatch information to a user.
[Service]
public class MyService: Service
{
// A notification requires an id that is unique to the application.
const int NOTIFICATION_ID = 9000;
// Work has finished, now dispatch anotification to let the user know.
Notification.Builder notificationBuilder = new Notification.Builder(this)
.SetSmallIcon(Resource.Drawable.ic_notification_small_icon)
.SetContentTitle(Resources.GetString(Resource.String.notification_content_title))
.SetContentText(Resources.GetString(Resource.String.notification_content_text));
When the user slides down the notification screen from the top, the full notification is displayed:
Updating A Notification
To update a notification, the service will republish the notification using the same notification ID. Android will
display or update the notification in the status bar as necessary.
void UpdateNotification(string content)
{
var notification = GetNotification(content, pendingIntent);
NotificationManager notificationManager =
(NotificationManager)GetSystemService(Context.NotificationService);
notificationManager.Notify(NOTIFICATION_ID, notification);
}
More information about notifications is available in the Local Notifications section of the Android Notifications
guide.
Related Links
Local Notifications in Android
Broadcast Receivers in Xamarin.Android
6/25/2018 • 8 minutes to read • Edit Online
When Xamarin.Android compiles the class, it will also update the AndroidManifest with the necessary meta-data
to register the receiver. For a statically-registered broadcast receiver, the Enabled properly must be set to true ,
otherwise Android will not be able to create an instance of the receiver.
The Exported property controls whether the broadcast receiver can receive messages from outside the
application. If the property is not explicitly set, the default value of the property is determined by Android based on
if there are any intent-filters associated with the broadcast receiver. If there is at least one intent-filter for the
broadcast receiver then Android will assume that the Exported property is true . If there are no intent-filters
associated with the broadcast receiver, then Android will assume that the value is false .
The OnReceive method receives a reference to the Intent that was dispatched to the broadcast receiver. This
makes is possible for the sender of the intent to pass values to the broadcast receiver.
Statically registering a Broadcast Receiver with an Intent Filter
When a BroadcastReceiver is decorated with the IntentFilterAttribute , Xamarin.Android will add the necessary
<intent-filter> element to the Android manifest at compile time. The following snippet is an example of a
broadcast receiver that will run when a device has finished booting (if the appropriate Android permissions were
granted by the user):
[BroadcastReceiver(Enabled = true)]
[IntentFilter(new[] { Android.Content.Intent.ActionBootCompleted })]
public class MyBootReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
// Work that should be done when the device boots.
}
}
It is also possible to create an intent filter that will respond to custom intents. Consider the following example:
[BroadcastReceiver(Enabled = true)]
[IntentFilter(new[] { "com.xamarin.example.TEST" })]
public class MySampleBroadcastReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
// Do stuff here
}
}
Apps that target Android 8.0 (API level 26) or higher may not statically register for an implicit broadcast. Apps
may still statically register for an explicit broadcast. There is a small list of of implicit broadcasts that are exempt
from this restriction. These exceptions are described in the Implicit Broadcast Exceptions guide in the Android
documentation. Apps that are interested in implicit broadcasts must do so dynamically using the RegisterReceiver
method. This is described next.
Context-Registering a Broadcast Receiver
Context-registration (also referred to as dynamic registration) of a receiver is performed by invoking the
RegisterReceiver method, and the broadcast receiver must be unregistered with a call to the UnregisterReceiver
method. To prevent leaking resources, it is important to unregister the receiver when it is no longer relevant for the
context (the Activity or service). For example, a service may broadcast an intent to inform an Activity that updates
are available to be displayed to the user. When the Activity starts, it would register for those Intents. When the
Activity is moved into the background and no longer visible to the user, it should unregister the receiver because
the UI for displaying the updates is no longer visible. The following code snippet is an example of how to register
and unregister a broadcast receiver in the context of an Activity:
In the previous example, when the Activity comes into the foreground, it will register a broadcast receiver that will
listen for a custom intent by using the OnResume lifecycle method. As the Activity moves into the background, the
OnPause() method will unregister the receiver.
Publishing a Broadcast
A broadcast may be published to all apps installed on the device creating an Intent object and dispatching it with
the SendBroadcast or the SendOrderedBroadcast method.
1. Context.SendBroadcast methods – There are several implementations of this method. These methods
will broadcast the intent to the entire system. Broadcast receivers thatwill receive the intent in an
indeterminate order. This provides a great deal of flexibility but means that it is possible for other
applications to register and receive the intent. This can pose a potential security risk. Applications may need
to implement addition security to prevent unauthorized access. One possible solution is to use the
LocalBroadcastManager which will only dispatch messages within the private space of the app. This code
snippet is one example of how to dispatch an intent using one of the SendBroadcast methods:
This snippet is another example of sending a broadcast by using the Intent.SetAction method to identify
the action:
Other apps on the device cannot receive the messages that are published with the LocalBroadcastManager . This
code snippet shows how to dispatch an Intent using the LocalBroadcastManager :
Related Links
BroadcastReceiver
Context.RegisterReceiver
Context.SendBroadcast
Context.UnregisterReceiver
Intent
IntentFilter
LocalBroadcastManager
Local Notifications in Android
Android Support Library v4
Android Localization
5/7/2018 • 6 minutes to read • Edit Online
This document introduces the localization features of the Android SDK and how to access them with Xamarin.
This value will be a locale identifier that contains both a language code and a locale code, separated by an
underscore. For reference, here is a list of Java locales and Android-supported locales via StackOverflow.
Common examples include:
en_US for English (United Statees)
es_ES for Spanish (Spain)
ja_JP for Japanese (Japan)
zh_CN for Chinese (China)
zh_TW for Chinese (Taiwan)
pt_PT for Portuguese (Portugal)
pt_BR for Portuguese (Brazil)
LOCALE_CHANGED
Android generates android.intent.action.LOCALE_CHANGED when the user changes their language selection.
Activities can opt to handle this by setting the android:configChanges attribute on the activity, like this:
NOTE
When specifying a top-level language like es only two characters are required; however when specifying a full locale, the
directory name format requires a dash and lowercase r to separate the two parts, for example pt-rBR or zh-rCN. Compare
this to the value returned in code, which has an underscore (eg. pt_BR ). Both of these are different to the value .NET
CultureInfo class uses, which has a dash only (eg. pt-BR ). Keep these differences in mind when working across Xamarin
platforms.
<string name="app_name">TaskyL10n</string>
You need to escape according to normal XML rules, and the name must be a valid Android resource ID (no spaces
or dashes). Here is an example of the default (English) strings file for the example:
values/Strings.xml
<resources>
<string name="app_name">TaskyL10n</string>
<string name="taskadd">Add Task</string>
<string name="taskname">Name</string>
<string name="tasknotes">Notes</string>
<string name="taskdone">Done</string>
<string name="taskcancel">Cancel</string>
</resources>
The Spanish directory values-es contains a file with the same name (Strings.xml) that contains the translations:
values-es/Strings.xml
With the strings files set-up, the translated values can be referenced in both layouts and code.
AXML Layout Files
To reference localized strings in layout files, use the @string/id syntax. This XML snippet from the sample shows
text properties being set with localized resource IDs (some other attributes have been omitted):
<TextView
android:id="@+id/NameLabel"
android:text="@string/taskname"
... />
<CheckBox
android:id="@+id/chkDone"
android:text="@string/taskdone"
... />
GetText Method
To retrieve translated strings in code, use the GetText method and pass the resource ID:
Quantity Strings
Android string resources also let you create quantity strings which allow translators to provide different
translations for different quantities, such as:
"There is 1 task left."
"There are 2 tasks still to do."
(rather than a generic "There are n task(s) left").
In the Strings.xml
<plurals name="numberOfTasks">
<!--
As a developer, you should always supply "one" and "other"
strings. Your translators will know which strings are actually
needed for their language.
-->
<item quantity="one">There is %d task left.</item>
<item quantity="other">There are %d tasks still to do.</item>
</plurals>
To render the complete string use the GetQuantityString method, passing the resource ID and the value to be
displayed (which is passed twice). The second parameter is used by Android to determine which quantity string
to use, the third parameter is the value actually substituted into the string (both are required).
Testing
Make sure to thoroughly test the default locale. Your application will crash if the default resources cannot be
loaded for some reason (i.e. they are missing).
Emulator Testing
Refer to Google's Testing on an Android Emulator section for instructions on how to set an emulator to a specific
locale using the ADB shell.
Device Testing
To test on a device, change the language in the Settings app. Tip: Make a note of the icons and location of the
menu items so that you can revert the language to the original setting.
Summary
This article covers the basics of localizing Android applications using the built-in resource handling. You can learn
more about i18n and L10n for iOS, Android and cross-platform (including Xamarin.Forms) apps in this cross-
platform guide.
Related Links
Tasky (localized in code) (sample)
Android Localizing with Resources
Cross-Platform Localization Overview
Xamarin.Forms Localization
iOS Localization
Permissions In Xamarin.Android
7/25/2018 • 9 minutes to read • Edit Online
Overview
Android applications run in their own sandbox and for security reasons do not have access to certain system
resources or hardware on the device. The user must explicitly grant permission to the app before it may use these
resources. For example, an application cannot access the GPS on a device without explicit permission from the
user. Android will throw a Java.Lang.SecurityException if an app tries to access a protected resource without
permission.
Permissions are declared in the AndroidManifest.xml by the application developer when the app is developed.
Android has two different workflows for obtaining the user's consent for those permissions:
For apps that targeted Android 5.1 (API level 22) or lower, the permission request occurred when the app was
installed. If the user did not grant the permissions, then the app would not be installed. Once the app is
installed, there is no way to revoke the permissions except by uninstalling the app.
Starting in Android 6.0 (API level 23), users were given more control over permissions; they can grant or
revoke permissions as long as the app is installed on the device. This screenshot shows the permission settings
for the Google Contacts app. It lists the various permissions and allows the user to enable or disable
permissions:
Android apps must check at run-time to see if they have permission to access a protected resource. If the app does
not have permission, then it must make requests using the new APIs provided by the Android SDK for the user to
grant the permissions. Permissions are divided into two categories:
Normal Permissions – These are permissions which pose little security risk to the user's security or privacy.
Android 6.0 will automatically grant normal permissions at the time of installation. Please consult the Android
documentation for a complete list of normal permissions.
Dangerous Permissions – In contrast to normal permissions, dangerous permissions are those that protect
the user's security or privacy. These must be explictly granted by the user. Sending or receiving an SMS
message is an example of an action requiring a dangerous permission.
IMPORTANT
The category that a permission belongs to may change over time. It is possible that a permission which was categorized as a
"normal" permission may be elevated in future API levels to a dangerous permission.
Dangerous permissions are further sub-divided into permission groups. A permission group will hold permissions
that are logically related. When the user grants permission to one member of a permission group, Android
automatically grants permission to all members of that group. For example, the STORAGE permission group holds
both the WRITE_EXTERNAL_STORAGE and READ_EXTERNAL_STORAGE permissions. If the user grants permission to
READ_EXTERNAL_STORAGE , then the WRITE_EXTERNAL_STORAGE permission is automatically granted at the same time.
Before requesting one or more permissions, it is a best practice to provide a rationale as to why the app requires
the permission before requesting the permission. Once the user understands the rationale, the app can request
permission from the user. By understanding the rationale, the user can make an informed decision if they wish to
grant the permission and understand the repercussions if they do not.
The whole workflow of checking and requesting permissions is known as a run-time permissions check, and can
be summarized in the following diagram:
The Android Support Library backports some of the new APIs for permissions to older versions of Android.
These backported APIs will automatically check the version of Android on the device so it is not necessary to
perform an API level check each time.
This document will discuss how to add permissions to a Xamarin.Android application and how apps that target
Android 6.0 (API level 23) or higher should perform a run-time permission check.
NOTE
It is possible that permissions for hardware may affect how the app is filtered by Google Play. For example, if the app
requires permission for the camera, then Google Play will not show the app in the Google Play Store on a device that does
not have a camera installed.
Requirements
It is strongly recommended that Xamarin.Android projects include the Xamarin.Android.Support.Compat NuGet
package. This package will backport permission specific APIs to older versions of Android, providing one common
interface without the need to constantly check the version of Android that the app is running on.
NOTE
Applications should only request the permissions that they require.
Visual Studio
Visual Studio for Mac
It is possible to declare the permissions using the tool support built into Visual Studio:
1. Double-click Properties in the Solution Explorer and select the Android Manifest tab in the Properties
window:
2. If the application does not already have an AndroidManifest.xml, click No AndroidManifest.xml found.
Click to add one as shown below:
3. Select any permissions your application needs from the Required permissions list and save:
Xamarin.Android will automatically add some permissions at build time to Debug builds. This will make
debugging the application easier. In particular, two notable permissions are INTERNET and READ_EXTERNAL_STORAGE .
These automatically-set permissions will not appear to be enabled in the Required permissions list. Release
builds, however, use only the permissions that are explicitly set in the Required permissions list.
For apps that target Android 5.1(API level 22) or lower, there is nothing more that needs to be done. Apps that will
run on Android 6.0 (API 23 level 23) or higher should proceed on to the next section on how to perform run time
permission checks.
Runtime Permission Checks in Android 6.0
The ContextCompat.CheckSelfPermission method (available with the Android Support Library) is used to check if a
specific permission has been granted. This method will return a Android.Content.PM.Permission enum which has
one of two values:
Permission.Granted – The specified permission has been granted.
Permission.Denied – The specified permission has not been granted.
This code snippet is an example of how to check for the Camera permission in an Activity:
It is a best practice to inform the user as to why a permission is necessary for an application so that an informed
decision can be made to grant the permission. An example of this would be an app that takes photos and geo-tags
them. It is clear to the user that the camera permission is necessary, but it might not be clear why the app also
needs the location of the device. The rationale should display a message to help the user understand why the
location permission is desirable and that the camera permission is required.
The ActivityCompat.ShouldShowRequestPermissionRational method is used to determine if the rationale should be
shown to the user. This method will return true if the rationale for a given permission should be displayed. This
screenshot shows an example of a Snackbar displayed by an application that explains why the app needs to know
the location of the device:
This code snippet is an example of the two methods that were discussed. First, a check is made to determine if the
permission rationale should be shown. If the rationale is to be shown, then a Snackbar is displayed with the
rationale. If the user clicks OK in the Snackbar, then the app will request the permissions. If the user does not
accept the rationale, then the app should not proceed to request permissions. If the rationale is not shown, then
the Activity will request the permission:
if (ActivityCompat.ShouldShowRequestPermissionRationale(this, Manifest.Permission.AccessFineLocation))
{
// Provide an additional rationale to the user if the permission was not granted
// and the user would benefit from additional context for the use of the permission.
// For example if the user has previously denied the permission.
Log.Info(TAG, "Displaying camera permission rationale to provide additional context.");
RequestPermission can be called even if the user has already granted permission. Subsequent calls are not
necessary, but they provide the user with the opportunity to confirm (or revoke) the permission. When
RequestPermission is called, control is handed off to the operating system, which will display a UI for accepting the
permissions:
After the user is finished, Android will return the results to the Activity via a callback method,
OnRequestPermissionResult . This method is a part of the interface
ActivityCompat.IOnRequestPermissionsResultCallback which must be implemented by the Activity. This interface
has a single method, OnRequestPermissionsResult , which will be invoked by Android to inform the Activity of the
user's choices. If the user has granted the permission, then the app can go ahead and use the protected resource.
An example of how to implement OnRequestPermissionResult is shown below:
Summary
This guide discussed how to add and check for permissions in an Android device. The differences in how
permissions work between old Android apps (API level < 23) and new Android apps (API level > 22). It discussed
how to perform run-time permission checks in Android 6.0.
Related Links
List of Normal Permissions
Runtime Permissions Sample App
Handling Permissions in Xamarin.Android
Graphics and Animation
4/12/2018 • 17 minutes to read • Edit Online
Android provides a very rich and diverse framework for supporting 2D graphics and animations. This topic
introduces these frameworks and discusses how to create custom graphics and animations for use in a
Xamarin.Android application.
Overview
Despite running on devices that are traditionally of limited power, the highest rated mobile applications often have
a sophisticated User Experience (UX), complete with high quality graphics and animations that provide an intuitive,
responsive, dynamic feel. As mobile applications get more and more sophisticated, users have begun to expect
more and more from applications.
Luckily for us, modern mobile platforms have very powerful frameworks for creating sophisticated animations and
custom graphics while retaining ease of use. This enables developers to add rich interactivity with very little effort.
UI API frameworks in Android can roughly be split into two categories: Graphics and Animation.
Graphics are further split into different approaches for doing 2D and 3D graphics. 3D graphics are available via a
number of built in frameworks such as OpenGL ES (a mobile specific version of OpenGL ), and third-party
frameworks such as MonoGame (a cross platform toolkit compatible with the XNA toolkit). Although 3D graphics
are not within the scope of this article, we will examine the built-in 2D drawing techniques.
Android provides two different API's for creating 2D graphics. One is a high level declarative approach and the
other a programmatic low -level API:
Drawable Resources – These are used to create custom graphics either programmatically or (more
typically) by embedding drawing instructions in XML files. Drawable resources are typically defined as XML
files that contain instructions or actions for Android to render a 2D graphic.
Canvas – this is a low level API that involves drawing directly on an underlying bitmap. It provides very
fine-grained control over what is displayed.
In addition to these 2D graphics techniques, Android also provides several different ways to create animations:
Drawable Animations – Android also supports frame-by-frame animations known as Drawable
Animation. This is the simplest animation API. Android sequentially loads and displays Drawable resources
in sequence (much like a cartoon).
View Animations – View Animations are the original animation API's in Android and are available in all
versions of Android. This API is limited in that it will only work with View objects and can only perform
simple transformations on those Views. View animations are typically defined in XML files found in the
/Resources/anim folder.
Property Animations – Android 3.0 introduced a new set of animation API's known as Property
Animations. These new API's introduced an extensible and flexible system that can be used to animate the
properties of any object, not just View objects. This flexibility allows animations to be encapsulated in
distinct classes that will make code sharing easier.
View Animations are more suitable for applications that must support the older pre-Android 3.0 API's (API level
11). Otherwise applications should use the newer Property Animation API's for the reasons that were mentioned
above.
All of these frameworks are viable options, however where possible, preference should be given to Property
Animations, as it is a more flexible API to work with. Property Animations allow for animation logic to be
encapsulated in distinct classes that makes code sharing easier and simplifies code maintenance.
Accessibility
Graphics and animations help to make Android apps attractive and fun to use; however, it is important to
remember that some interactions occur via screenreaders, alternate input devices, or with assisted zoom. Also,
some interactions may occur without audio capabilities.
Apps are more usable in these situations if they have been designed with accessibility in mind: providing hints and
navigation assistance in the user-interface, and ensuring there is text-content or descriptions for pictorial elements
of the UI.
Refer to Google's Accessibility Guide for more information on how to utilize Android's accessibility APIs.
2D Graphics
Drawable Resources are a popular technique in Android applications. As with other resources, Drawable Resources
are declarative – they're defined in XML files. This approach allows for a clean separation of code from resources.
This can simplify development and maintenance because it is not necessary to change code to update or change
the graphics in an Android application. However, while Drawable Resources are useful for many simple and
common graphic requirements, they lack the power and control of the Canvas API.
The other technique, using the Canvas object, is very similar to other traditional API frameworks such as
System.Drawing or iOS's Core Drawing. Using the Canvas object provides the most control of how 2D graphics
are created. It is appropriate for situations where a Drawable Resource will not work or will be difficult to work
with. For example, it may be necessary to draw a custom slider control whose appearance will change based on
calculations related to the value of the slider.
Let's examine Drawable Resources first. They are simpler and cover the most common custom drawing cases.
Drawable Resources
Drawable Resources are defined in an XML file in the directory /Resources/drawable . Unlike embedding PNG or
JPEG's, it is not necessary to provide density-specific versions of Drawable Resources. At runtime, an Android
application will load these resources and use the instructions contained in these XML files to create 2D graphics.
Android defines several different types of Drawable Resources:
ShapeDrawable – This is a Drawable object that draws a primitive geometric shape and applies a limited set
of graphical effects on that shape. They are very useful for things such as customizing Buttons or setting the
background of TextViews. We will see an example of how to use a ShapeDrawable later in this article.
StateListDrawable – This is a Drawable Resource that will change appearance based on the state of a
widget/control. For example, a button may change its appearance depending on whether it is pressed or not.
LayerDrawable – This Drawable Resource that will stack several other drawables one on top of another. An
example of a LayerDrawable is shown in the following screenshot:
<padding android:left="5dp"
android:right="5dp"
android:top="5dp"
android:bottom="5dp" />
<corners android:topLeftRadius="10dp"
android:topRightRadius="10dp"
android:bottomLeftRadius="10dp"
android:bottomRightRadius="10dp" />
</shape>
We can reference this Drawable Resource declaratively in a Layout or other Drawable as shown in the following
XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#33000000">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@drawable/shape_rounded_blue_rect"
android:text="@string/message_shapedrawable" />
</RelativeLayout>
Drawable Resources can also be applied programmatically. The following code snippet shows how to
programmatically set the background of a TextView:
TextView tv = FindViewById<TextView>(Resource.Id.shapeDrawableTextView);
tv.SetBackgroundResource(Resource.Drawable.shape_rounded_blue_rect);
To see what this would look like, run the AnimationsDemo project and select the Shape Drawable item from the
main menu. We should see something similar to the following screenshot:
For more details about the XML elements and syntax of Drawable Resources, consult Google's documentation.
Using the Canvas Drawing API
Drawables are powerful but have their limitations. Certain things are either not possible or very complex (for
example: applying a filter to a picture that was taken by a camera on the device). It would be very difficult to apply
red-eye reduction by using a Drawable Resource. Instead, the Canvas API allows an application to have very fine-
grained control to selectively change colors in a specific part of the picture.
One class that is commonly used with the Canvas is the Paint class. This class holds colour and style information
about how to draw. It is used to provide things such a color and transparency.
The Canvas API uses the painter's model to draw 2D graphics. Operations are applied in successive layers on top
of each other. Each operation will cover some area of the underlying bitmap. When the area overlaps a previously
painted area, the new paint will partially or completely obscure the old. This is the same way that many other
drawing APIs such as System.Drawing and iOS's Core Graphics work.
There are two ways to obtain a Canvas object. The first way involves defining a Bitmap object, and then
instantiating a Canvas object with it. For example, the following code snippet creates a new canvas with an
underlying bitmap:
The other way to obtain a Canvas object is by the OnDraw callback method that is provided the View base class.
Android calls this method when it decides a View needs to draw itself and passes in a Canvas object for the View
to work with.
The Canvas class exposes methods to programmatically provide the draw instructions. For example:
Canvas.DrawPaint – Fills the entire canvas's bitmap with the specified paint.
Canvas.DrawPath – Draws the specified geometric shape using the specified paint.
Canvas.DrawText – Draws the text on the canvas with the specified colour. The text is drawn at location x,y
.
Drawing with the Canvas API
Let's see an example of the Canvas API in action. The following code snippet shows how to draw a view:
public class MyView : View
{
protected override void OnDraw(Canvas canvas)
{
base.OnDraw(canvas);
Paint green = new Paint {
AntiAlias = true,
Color = Color.Rgb(0x99, 0xcc, 0),
};
green.SetStyle(Paint.Style.FillAndStroke);
This code above first creates a red paint and a green paint object. It fills the content of the canvas with red, and
then instructs the canvas to draw a green rectangle that is 25% of the width of the canvas. An example of this can
be seen by in AnimationsDemo project that is included with the source code for this article. By starting up the
application and selecting the Drawing item from the main menu, we should a screen similar to the following:
Animation
Users like things that move in their applications. Animations are a great way to improve the user experience of an
application and help it stand out. The best animations are the ones that users don't notice because they feel natural.
Android provides the following three API's for animations:
View Animation – This is the original API. These animations are tied to a specific View and can perform
simple transformations on the contents of the View. Because of it's simplicity, this API still useful for things
like alpha animations, rotations, and so forth.
Property Animation – Property animations were introduced in Android 3.0. They enable an application to
animate almost anything. Property animations can be used to change any property of any object, even if
that object is not visible on the screen.
Drawable Animation – This a special Drawable resource that is used to apply a very simple animation
effect to layouts.
In general, property animation is the preferred system to use as it is more flexible and offers more features.
View Animations
View animations are limited to Views and can only perform animations on values such as start and end points,
size, rotation, and transparency. These types of animations are typically referred to as tween animations. View
animations can be defined two ways – programmatically in code or by using XML files. XML files are the preferred
way to declare view animations, as they are more readable and easier to maintain.
The animation XML files will be stored in the /Resources/anim directory of a Xamarin.Android project. This file
must have one of the following elements as the root element :
alpha – A fade-in or fade-out animation.
rotate – A rotation animation.
scale – A resizing animation.
translate – A horizontal and/or vertical motion.
set – A container that may hold one or more of the other animation elements.
By default, all animations in an XML file will be applied simultaneously. To make animations occur sequentially, set
the android:startOffset attribute on one of the elements defined above.
It is possible to affect the rate of change in an animation by using an interpolator. An interpolator makes it possible
for animation effects to be accelerated, repeated, or decelerated. The Android framework provides several
interpolators out of the box, such as (but not limited to):
AccelerateInterpolator / DecelerateInterpolator – these interpolators increase or decrease the rate of
change in an animation.
BounceInterpolator – the change bounces at the end.
LinearInterpolator – the rate of changes is constant.
The following XML shows an example of an animation file that combines some of these elements:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android=http://schemas.android.com/apk/res/android
android:shareInterpolator="false">
<scale android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromXScale="1.0"
android:toXScale="1.4"
android:fromYScale="1.0"
android:toYScale="0.6"
android:pivotX="50%"
android:pivotY="50%"
android:fillEnabled="true"
android:fillAfter="false"
android:duration="700" />
<set android:interpolator="@android:anim/accelerate_interpolator">
<scale android:fromXScale="1.4"
android:toXScale="0.0"
android:fromYScale="0.6"
android:toYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:fillEnabled="true"
android:fillBefore="false"
android:fillAfter="true"
android:startOffset="700"
android:duration="400" />
<rotate android:fromDegrees="0"
android:toDegrees="-45"
android:toYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:fillEnabled="true"
android:fillBefore="false"
android:fillAfter="true"
android:startOffset="700"
android:duration="400" />
</set>
</set>
This animation will perform all of the animations simultaneously. The first scale animation will stretch the image
horizontally and shrink it vertically, and then the image will simultaneously be rotated 45 degrees counter-
clockwise and shrink, disappearing from the screen.
The animation can be programmatically applied to a View by inflating the animation and then applying it to a View.
Android provides the helper class Android.Views.Animations.AnimationUtils that will inflate an animation resource
and return an instance of Android.Views.Animations.Animation . This object is applied to a View by calling
StartAnimation and passing the Animation object. The following code snippet shows an example of this:
Now that we have a fundamental understanding of how View Animations work, lets move to Property Animations.
Property Animations
Property animators are a new API that was introduced in Android 3.0. They provide a more extensible API that can
be used to animate any property on any object.
All property animations are created by instances of the Animator subclass. Applications do not directly use this
class, instead they use one of it's subclasses:
ValueAnimator – This class is the most important class in the entire property animation API. It calculates the
values of properties that need to be changed. The ViewAnimator does not directly update those values;
instead, it raises events that can be used to update animated objects.
ObjectAnimator – This class is a subclass of ValueAnimator . It is meant to simplify the process of animating
objects by accepting a target object and property to update.
AnimationSet – This class is responsible for orchestrating how animations run in relation to one another.
Animations may run simultaneously, sequentially, or with a specified delay between them.
Evaluators are special classes that are used by animators to calculate the new values during an animation. Out of
the box, Android provides the following evaluators:
IntEvaluator – Calculates values for integer properties.
FloatEvaluator – Calculates values for float properties.
ArgbEvaluator – Calculates values for colour properties.
If the property that is being animated is not a float , int or colour, applications may create their own evaluator
by implementing the ITypeEvaluator interface. (Implementing custom evaluators is beyond the scope of this
topic.)
Using the ValueAnimator
There are two parts to any animation: calculating animated values and then setting those values on properties on
some object. ValueAnimator will only calculate the values, but it will not operate on objects directly. Instead, objects
will be updated inside event handlers that will be invoked during the animation lifespan. This design allows several
properties to be updated from one animated value.
You obtain an instance of ValueAnimator by calling one of the following factory methods:
ValueAnimator.OfInt
ValueAnimator.OfFloat
ValueAnimator.OfObject
Once that is done, the ValueAnimator instance must have its duration set, and then it can be started. The following
example shows how to animate a value from 0 to 1 over the span of 1000 milliseconds:
But itself, the code snippet above is not very useful – the animator will run but there is no target for the updated
value. The Animator class will raise the Update event when it decides that it is necessary to inform listeners of a
new value. Applications may provide an event handler to respond to this event as shown in the following code
snippet:
As you can see from the previous code snippet, ObjectAnimator can reduce and simplify the code that is necessary
to animate an object.
Drawable Animations
The final animation API is the Drawable Animation API. Drawable animations load a series of Drawable resources
one after the other and display them sequentially, similar to a flip-it cartoon.
Drawable resources are defined in an XML file that has an <animation-list> element as the root element and a
series of <item> elements that define each frame in the animation. This XML file is stored in the
/Resource/drawable folder of the application. The following XML is an example of a drawable animation:
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/asteroid01" android:duration="100" />
<item android:drawable="@drawable/asteroid02" android:duration="100" />
<item android:drawable="@drawable/asteroid03" android:duration="100" />
<item android:drawable="@drawable/asteroid04" android:duration="100" />
<item android:drawable="@drawable/asteroid05" android:duration="100" />
<item android:drawable="@drawable/asteroid06" android:duration="100" />
</animation-list>
This animation will run through six frames. The android:duration attribute declares how long each frame will be
displayed. The next code snippet shows an example of creating a Drawable animation and starting it when the user
clicks a button on the screen:
AnimationDrawable _asteroidDrawable;
_asteroidDrawable = (Android.Graphics.Drawables.AnimationDrawable)
Resources.GetDrawable(Resource.Drawable.spinning_asteroid);
At this point we have covered the foundations of the animation APIs available in an Android application.
Summary
This article introduced a lot of new concepts and API's to help add some graphics to an Android application. First it
discussed the various 2D graphics API's and demonstrated how Android allows applications to draw directly to the
screen using a Canvas object. We also saw some alternate techniques that allow graphics to be declaratively
created using XML files. Then we went on to discuss the old and new API's for creating animations in Android.
Related Links
Animation Demo (sample)
Animation and Graphics
Using Animations to Bring your Mobile Apps to Life
AnimationDrawable
Canvas
Object Animator
Value Animator
CPU Architectures
5/18/2018 • 3 minutes to read • Edit Online
Xamarin.Android supports several CPU architectures, including 32 -bit and 64 -bit devices. This article explains how
to target an app to one or more Android -supported CPU architectures.
NOTE
64-bit runtime support is currently an experimental feature. Remember that 64-bit runtimes are not required to run your
app on 64-bit devices.
Additional Information
In some situations, you may need to create a separate APK for each architecture (to reduce the size of your APK,
or because your app has shared libraries that are specific to a particular CPU architecture). For more information
about this approach, see Build ABI-Specific APKs.
Handling Rotation
4/12/2018 • 8 minutes to read • Edit Online
This topic describes how to handle device orientation changes in Xamarin.Android. It covers how to work with the
Android resource system to automatically load resources for a particular device orientation as well as how to
programmatically handle orientation changes.
Overview
Because mobile devices are easily rotated, built-in rotation is a standard feature in mobile OSes. Android provides
a sophisticated framework for dealing with rotation within applications, whether the user interface is created
declaratively in XML or programmatically in code. When automatically handling declarative layout changes on a
rotated device, an application can benefit from the tight integration with the Android resource system. For
programmatic layout, changes must be handled manually. This allows finer control at runtime, but at the expense
of more work for the developer. An application can also choose to opt out of the Activity restart and take manual
control of orientation changes.
This guide examines the following orientation topics:
Declarative Layout Rotation – How to use the Android resource system to build orientation-aware
applications, including how to load both layouts and drawables for particular orientations.
Programmatic Layout Rotation – How to add controls programmatically as well as how to handle
orientation changes manually.
If the device is rotated to landscape orientation, the Activity's OnCreate method is called again and the same
Main.axml file is inflated, as shown in the screenshot below:
Orientation-Specific Layouts
In addition to the layout folder (which defaults to portrait and can also be explicitly named layout-port by
including a folder named layout-land ), an application can define the views it needs when in landscape without
any code changes.
Suppose the Main.axml file contained the following XML:
If a folder named layout-land that contains an additional Main.axml file is added to the project, inflating the
layout when in landscape will now result in Android loading the newly added Main.axml. Consider the landscape
version of the Main.axml file that contains the following code (for simplicity, this XML is similar to the default
portrait version of the code, but uses a different string in the TextView ):
Running this code and rotating the device from portrait to landscape demonstrates the new XML loading, as
shown below:
Drawable Resources
During rotation, Android treats drawable resources similarly to layout resources. In this case, the system gets the
drawables from the Resources/drawable and Resources/drawable-land folders, respectively.
For example, say the project includes an image named Monkey.png in the Resources/drawable folder, where the
drawable is referenced from an ImageView in XML like this:
<ImageView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/monkey"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
Let's further assume that a different version of Monkey.png is included under Resources/drawable-land. Just
like with the layout files, when the device is rotated, the drawable changes for the given orientation, as shown
below:
Handling Rotation Programmatically
Sometimes we define layouts in code. This can happen for a variety of reasons, including technical limitations,
developer preference, etc. When we add controls programmatically, an application must manually account for
device orientation, which is handled automatically when we use XML resources.
Adding Controls in Code
To add controls programmatically, an application needs to perform the following steps:
Create a layout.
Set layout parameters.
Create controls.
Set control layout parameters.
Add controls to the layout.
Set the layout as the content view.
For example, consider a user interface consisting of a single TextView control added to a RelativeLayout , as
shown in the following code.
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// create a layout
var rl = new RelativeLayout (this);
This code creates an instance of a RelativeLayout class and sets its LayoutParameters property. The LayoutParams
class is Android's way of encapsulating how controls are positioned in a reusable way. Once an instance of a
layout is created, controls can be created and added to it. Controls also have LayoutParameters , such as the
TextView in this example. After the TextView is created, adding it to the RelativeLayout and setting the
RelativeLayout as the content view results in the application displaying the TextView as shown:
// create a layout
var rl = new RelativeLayout (this);
This code sets the TextView to be positioned 100 pixels from the top left of the screen, automatically animating to
the new layout, when rotated to landscape, as shown here:
Preventing Activity Restart
In addition to handling everything in OnCreate , an application can also prevent an Activity from being restarted
when the orientation changes by setting ConfigurationChanges in the ActivityAttribute as follows:
Now when the device is rotated, the Activity is not restarted. In order to manually handle the orientation change in
this case, an Activity can override the OnConfigurationChanged method and determine the orientation from the
Configuration object that is passed in, as in the new implementation of the Activity below:
if (newConfig.Orientation == Android.Content.Res.Orientation.Portrait) {
_tv.LayoutParameters = _layoutParamsPortrait;
_tv.Text = "Changed to portrait";
} else if (newConfig.Orientation == Android.Content.Res.Orientation.Landscape) {
_tv.LayoutParameters = _layoutParamsLandscape;
_tv.Text = "Changed to landscape";
}
}
}
Here the TextView's layout parameters are initialized for both landscape and portrait. Class variables hold the
parameters, along with the TextView itself, since the Activity will not be re-created when orientation changes. The
code still uses the surfaceOrientartion in OnCreate to set the initial layout for the TextView . After that,
OnConfigurationChanged handles all subsequent layout changes.
When we run the application, Android loads the user interface changes as device rotation occurs, and does not
restart the Activity.
Summary
This article covered how to use Android's built-in capabilities to work with rotation. First, it explained how to use
the Android resource system to create orientation aware applications. Then it presented how to add controls in
code as well as how to handle orientation changes manually.
Related Links
Rotation Demo (sample)
Activity Lifecycle
Handling Runtime Changes
Fast Screen Orientation Change
Android Audio
4/12/2018 • 10 minutes to read • Edit Online
The Android OS provides extensive support for multimedia, encompassing both audio and video. This guide
focuses on audio in Android and covers playing and recording audio using the built-in audio player and recorder
classes, as well as the low -level audio API. It also covers working with Audio events broadcast by other
applications, so that developers can build well-behaved applications.
Overview
Modern mobile devices have adopted functionality that formerly would have required dedicated pieces of
equipment – cameras, music players and video recorders. Because of this, multimedia frameworks have become a
first-class feature in mobile APIs.
Android provides extensive support for multimedia. This article examines working with audio in Android, and
covers the following topics
1. Playing Audio with MediaPlayer – Using the built-in MediaPlayer class to play audio, including local
audio files and streamed audio files with the AudioTrack class.
2. Recording Audio – Using the built-in MediaRecorder class to record audio.
3. Working with Audio Notifications – Using audio notifications to create well-behaved applications that
respond correctly to events (such as incoming phone calls) by suspending or canceling their audio outputs.
4. Working with Low-Level Audio – Playing audio using the AudioTrack class by writing directly to
memory buffers. Recording audio using the AudioRecord class and reading directly from memory buffers.
Requirements
This guide requires Android 2.0 (API level 5) or higher. Please note that debugging audio on Android must be
done on a device.
It is necessary to request the RECORD_AUDIO permissions in AndroidManifest.XML:
Playing Audio with the MediaPlayer Class
The simplest way to play audio in Android is with the built-in MediaPlayer class. MediaPlayer can play either local
or remote files by passing in the file path. However, MediaPlayer is very state-sensitive and calling one of its
methods in the wrong state will cause an exception to be thrown. It's important to interact with MediaPlayer in the
order described below to avoid errors.
Initializing and Playing
Playing audio with MediaPlayer requires the following sequence:
1. Instantiate a new MediaPlayer object.
2. Configure the file to play via the SetDataSource method.
3. Call the Prepare method to initialize the player.
4. Call the Start method to start the audio playing.
The code sample below illustrates this usage:
protected MediaPlayer player;
public void StartPlayer(String filePath)
{
if (player == null) {
player = new MediaPlayer();
} else {
player.Reset();
player.SetDataSource(filePath);
player.Prepare();
player.Start();
}
}
player.Pause();
To resume paused playback, call the Start method. This will resume from the paused location in the playback:
player.Start();
player.Stop();
When the player is no longer needed, the resources must be released by calling the Release method:
player.Release();
Stopping recording
To stop the recording, call the Stop method on the MediaRecorder :
recorder.Stop();
Cleaning up
Once the MediaRecorder has been stopped, call the Reset method to put it back into its idle state:
recorder.Reset();
When the MediaRecorder is no longer needed, its resources must be released by calling the Release method:
recorder.Release();
audioTrack.Play();
audioTrack.Write(audioBuffer, 0, audioBuffer.Length);
}
audioTrack.Pause();
audioTrack.Stop();
Cleanup
When the AudioTrack is no longer needed, its resources must be released by calling Release:
audioTrack.Release();
audRecorder.Stop();
Cleanup
When the AudioRecord object is no longer needed, calling its Release method releases all resources associated
with it:
audRecorder.Release();
Summary
The Android OS provides a powerful framework for playing, recording and managing audio. This article covered
how to play and record audio using the high-level MediaPlayer and MediaRecorder classes. Next, it explored how
to use audio notifications to share the audio resources of the device between different applications. Finally, it dealt
with how to playback and record audio using the low -level APIs, which interface directly with memory buffers.
Related Links
Working With Audio (sample)
Media Player
Media Recorder
Audio Manager
Audio Track
Audio Recorder
Notifications in Xamarin.Android
4/12/2018 • 2 minutes to read • Edit Online
Overview
This section explains how to implement notifications in Xamarin.Android. It describes the various UI elements of
an Android notification and discusses the API's involved with creating and displaying a notification.
Sections
Local Notifications In Android
This section explains how to implement local notifications in Xamarin.Android. It describes the various UI
elements of an Android notification and discuss the API's involved with creating and displaying a notification.
Walkthrough - Using Local Notifications in Xamarin.Android
This walkthrough covers how to use local notifications in a Xamarin.Android application. It demonstrates the
basics of creating and publishing a notification. When the user clicks on the notification in the notification drawer
it starts up a second Activity.
Related Links
Local Notifications (sample)
Remote Notifications (sample)
Local Notifications
7/25/2018 • 30 minutes to read • Edit Online
This section shows how to implement local notifications in Xamarin.Android. It explains the various UI elements
of an Android notification and discusses the API's involved with creating and displaying a notification.
To obtain details about the notification, the user can open the notification drawer (which expands each
notification icon to reveal notification content) and perform any actions associated with the notifications. The
following screen shot shows a notification drawer that corresponds to the notification area displayed above:
Base layouts are limited to 64 density-independent pixels (dp) in height. Android creates this basic notification
style by default.
Optionally, notifications can display a large icon that represents the application or the sender's photo. When a
large icon is used in a notification in Android 5.0 and later, the small notification icon is displayed as a badge over
the large icon:
Beginning with Android 5.0, notifications can also appear on the lockscreen:
The user can double-tap the lockscreen notification to unlock the device and jump to the app that originated that
notification, or swipe to dismiss the notification. Apps can set the visibility level of a notification to control what is
shown on the lockscreen, and users can choose whether to allow sensitive content to be shown in lockscreen
notifications.
Android 5.0 introduced a high-priority notification presentation format called Heads-up. Heads-up notifications
slide down from the top of the screen for a few seconds and then retreat back up to the notification area:
Heads-up notifications make it possible for the system UI to put important information in front of the user
without disrupting the state of the currently running activity.
Android includes support for notification metadata so that notifications can be sorted and displayed intelligently.
Notification metadata also controls how notifications are presented on the lockscreen and in Heads-up format.
Applications can set the following types of notification metadata:
Priority – The priority level determines how and when notifications are presented. For example, In
Android 5.0, high-priority notifications are displayed as Heads-up notifications.
Visibility – Specifies how much notification content is to be displayed when the notification appears on
the lockscreen.
Category – Informs the system how to handle the notification in various circumstances, such as when the
device is in Do not Disturb mode.
Note: Visibility and Category were introduced in Android 5.0 and are not available in earlier versions of
Android. Beginning with Android 8.0, notification channels are used to control how notifications are presented to
the user.
Expanded Layouts
Beginning with Android 4.1, notifications can be configured with expanded layout styles that allow the user to
expand the height of the notification to view more content. For example, the following example illustrates an
expanded layout notification in contracted mode:
Notification Creation
To create a notification in Android, you use the Notification.Builder class. Notification.Builder was introduced
in Android 3.0 to simplify the creation of notification objects. To create notifications that are compatible with
older versions of Android, you can use the NotificationCompat.Builder class instead of Notification.Builder
(see Compatibility later in this topic for more information about using NotificationCompat.Builder ).
Notification.Builder provides methods for setting the various options in a notification, such as:
The content, including the title, the message text, and the notification icon.
The style of the notification, such as Big Text, Inbox, or Image style.
The priority of the notification: minimum, low, default, high, or maximum.
The visibility of the notification on the lockscreen: public, private, or secret.
Category metadata that helps Android classify and filter the notification.
An optional intent that indicates an activity to launch when the notification is tapped.
After you set these options in the builder, you generate a notification object that contains the settings. To publish
the notification, you pass this notification object to the Notification Manager. Android provides the
NotificationManager class, which is responsible for publishing notifications and displaying them to the user. A
reference to this class can be obtained from any context, such as an activity or a service.
How to Generate a Notification
To generate a notification in Android, follow these steps:
1. Instantiate a Notification.Builder object.
2. Call various methods on the Notification.Builder object to set notification options.
3. Call the Build method of the Notification.Builder object to instantiate a notification object.
4. Call the Notify method of the notification manager to publish the notification.
You must provide at least the following information for each notification:
A small icon (24x24 dp in size)
A short title
The text of the notification
The following code example illustrates how to use Notification.Builder to generate a basic notification. Notice
that Notification.Builder methods support method chaining; that is, each method returns the builder object so
you can use the result of the last method call to invoke the next method call:
In this example, a new Notification.Builder object called builder is instantiated, the title and text of the
notification are set, and the notification icon is loaded from Resources/drawable/ic_notification.png. The call
to the notification builder's Build method creates a notification object with these settings. The next step is to call
the Notify method of the notification manager. To locate the notification manager, you call GetSystemService , as
shown above.
The Notify method accepts two parameters: the notification identifier and the notification object. The
notification identifier is a unique integer that identifies the notification to your application. In this example, the
notification identifier is set to zero (0); however, in a production application, you will want to give each
notification a unique identifier. Reusing the previous identifier value in a call to Notify causes the last
notification to be overwritten.
When this code runs on an Android 5.0 device, it generates a notification that looks like the following example:
The notification icon is displayed on the left hand side of the notification – this image of a circled “i” has an alpha
channel so that Android can draw a gray circular background behind it. You can also supply an icon without an
alpha channel. To display a photographic image as an icon, see Large Icon Format later in this topic.
The timestamp is set automatically, but you can override this setting by calling the SetWhen method of the
notification builder. For example, the following code example sets the timestamp to the current time:
builder.SetWhen (Java.Lang.JavaSystem.CurrentTimeMillis());
This call to SetDefaults will cause the device to play a sound when the notification is published. If you want the
device to vibrate rather than play a sound, you can pass NotificationDefaults.Vibrate to SetDefaults. If you
want the device to play a sound and vibrate the device, you can pass both flags to SetDefaults :
If you enable sound without specifying a sound to play, Android uses the default system notification sound.
However, you can change the sound that will be played by calling the notification builder's SetSound method.
For example, to play the alarm sound with your notification (instead of the default notification sound), you can
get the URI for the alarm sound from the RingtoneManager and pass it to SetSound :
builder.SetSound (RingtoneManager.GetDefaultUri(RingtoneType.Alarm));
Alternatively, you can use the system default ringtone sound for your notification:
builder.SetSound (RingtoneManager.GetDefaultUri(RingtoneType.Ringtone));
After you create a notification object, it's possible to set notification properties on the notification object (rather
than configure them in advance through Notification.Builder methods). For example, instead of calling the
SetDefaults method to enable vibration on a notification, you can directly modify the bit flag of the notification's
Defaults property:
// Turn on vibrate:
notification.Defaults |= NotificationDefaults.Vibrate;
This example causes the device to vibrate when the notification is published.
Updating a Notification
If you want to update the content of a notification after it has been published, you can reuse the existing
Notification.Builder object to create a new notification object and publish this notification with the identifier of
the last notification. For example:
In this example, the existing Notification.Builder object is used to create a new notification object with a
different title and message. The new notification object is published using the identifier of the previous
notification, and this updates the content of the previously-published notification:
The body of the previous notification is reused – only the title and the text of the notification changes while the
notification is displayed in the notification drawer. The title text changes from "Sample Notification" to "Updated
Notification" and the message text changes from "Hello World! This is my first notification!" to "Changed to this
message."
A notification remains visible until one of three things happens:
The user dismisses the notification (or taps Clear All).
The application makes a call to NotificationManager.Cancel , passing in the unique notification ID that was
assigned when the notification was published.
The application calls NotificationManager.CancelAll .
For more about updating Android notifications, see Modify a Notification.
Starting an Activity from a Notification
In Android, it's common for a notification to be associated with an action – an activity that's launched when the
user taps the notification. This activity can reside in another application or even in another task. To add an action
to a notification, you create a PendingIntent object and associate the PendingIntent with the notification. A
PendingIntent is a special type of intent that allows the recipient application to run a predefined piece of code
with the permissions of the sending application. When the user taps the notification, Android starts up the
activity specified by the PendingIntent .
The following code snippet illustrates how to create a notification with a PendingIntent that will launch the
activity of the originating app, MainActivity :
// Instantiate the builder and set notification elements, including pending intent:
Notification.Builder builder = new Notification.Builder(this)
.SetContentIntent (pendingIntent)
.SetContentTitle ("Sample Notification")
.SetContentText ("Hello World! This is my first action notification!")
.SetSmallIcon (Resource.Drawable.ic_notification);
Tapping this notification takes the user back to the originating activity.
In a production app, your app must handle the back stack when the user presses the Back button within the
notification activity (if you are not familiar with Android tasks and the back stack, see Tasks and Back Stack). In
most cases, navigating backward out of the notification activity should return the user out of the app and back to
Home screen. To manage the back stack, your app uses the TaskStackBuilder class to create a PendingIntent
with a back stack.
Another real-world consideration is that the originating activity may need to send data to the notification activity.
For example, the notification may indicate that a text message has arrived, and the notification activity (a
message viewing screen), requires the ID of the message to display the message to the user. The activity that
creates the PendingIntent can use the Intent.PutExtra method to add data (for example, a string) to the intent so
that this data is passed to the notification activity.
The following code sample illustrates how to use TaskStackBuilder to manage the back stack, and it includes an
example of how to send a single message string to a notification activity called SecondActivity :
// Setup an intent for SecondActivity:
Intent secondIntent = new Intent (this, typeof(SecondActivity));
In this code example, the app consists of two activities: MainActivity (which contains the notification code
above), and SecondActivity , the screen the user sees after tapping the notification. When this code is run, a
simple notification (similar to the previous example) is presented. Tapping on the notification takes the user to
the SecondActivity screen:
The string message (passed into the intent's PutExtra method) is retrieved in SecondActivity via this line of
code:
Notification Channels
Beginning with Android 8.0 (Oreo), you can use the notification channels feature to create a user-customizable
channel for each type of notification that you want to display. Notification channels make it possible for you to
group notifications so that all notifications posted to a channel exhibit the same behavior. For example, you might
have a notification channel that is intended for notifications that require immediate attention, and a separate
"quieter" channel that is used for informational messages.
The YouTube app that is installed with Android Oreo lists two notification categories: Download notifications
and General notifications:
Each of these categories corresponds to a notification channel. The YouTube app implements a Download
notifications channel and a General Notifications channel. The user can tap Download notifications, which
displays the settings screen for the app's download notifications channel:
In this screen, the user can modify the behavior of the Download notifications channel by doing the following:
Set the Importance level to Urgent, High, Medium, or Low, which configures the level of sound and
visual interruption.
Turn the notification dot on or off.
Turn the blinking light on or off.
Show or hide notifications on the lock screen.
Override the Do Not Disturb setting.
The General Notifications channel has similar settings:
Notice that you do not have absolute control over how your notification channels interact with the user – the
user can modify the settings for any notification channel on the device as seen in the screenshots above.
However, you can configure default values (as will be described below ). As these examples illustrate, the new
notification channels feature makes it possible for you to give users fine-grained control over different kinds of
notifications.
Should you add support for notification channels to your app? If you're targeting Android 8.0, your app must
implement notification channels. An app targeted for Oreo that attempts to send a local notification to the user
without using a notification channel will fail to display the notification on Oreo devices. If you don't target
Android 8.0, your app will still run on Android 8.0, but with the same notification behavior as it would exhibit
when running on Android 7.1 or earlier.
Creating a Notification Channel
To create a notification channel, do the following:
1. Construct a NotificationChannel object with the following:
An ID string that is unique within your package. In the following example, the string
com.xamarin.myapp.urgent is used.
The user-visible name of the channel (less than 40 characters). In the following example, the name
Urgent is used.
The importance of the channel, which controls how interruptive notifications are posted to the
NotificationChannel . The importance can be Default , High , Low , Max , Min , None , or
Unspecified .
Pass these values to the constructor (in this example, Resource.String.noti_chan_urgent is set to Urgent):
2. Configure the NotificationChannel object with initial settings. For example, the following code configures
the NotificationChannel object so that notifications posted to this channel will vibrate the device and
appear on the lock screen by default:
chan.EnableVibration (true);
chan.LockscreenVisibility = NotificationVisibility.Public;
NotificationManager notificationManager =
(NotificationManager) GetSystemService (NotificationService);
notificationManager.CreateNotificationChannel (chan);
2. Build and issue the notification using the Notification Manager's Notify method:
const int notificationId = 0;
notificationManager.Notify (notificationId, builder.Build());
You can repeat the above steps to create another notification channel for informational messages. This second
channel could, by default, disable vibration, set the default lock screen visibility to Private , and set the
notification importance to Default .
For a complete code example of Android Oreo Notification Channels in action, see the NotificationChannels
sample; this sample app manages two channels and sets additional notification options.
And here is a screenshot of the notification after modifying it to display a large icon – it uses an icon created
from an image of a Xamarin code monkey:
Notice that when a notification is presented in large icon format, the small app icon is displayed as a badge on
the lower right corner of the large icon.
To use an image as a large icon in a notification, you call the notification builder's SetLargeIcon method and pass
in a bitmap of the image. Unlike SetSmallIcon , SetLargeIcon only accepts a bitmap. To convert an image file
into a bitmap, you use the BitmapFactory class. For example:
This example code opens the image file at Resources/drawable/monkey_icon.png, converts it to a bitmap,
and passes the resulting bitmap to Notification.Builder . Typically, the source image resolution is larger than the
small icon – but not much larger. An image that is too large might cause unnecessary resizing operations that
could delay the posting of the notification. For more about notification icon sizes in Android, see Notification
Icons.
Big Text Style
The Big Text style is an expanded layout template that you use for displaying long messages in notifications. Like
all expanded layout notifications, the Big Text notification is initially displayed in a compact presentation format:
In this format, only an excerpt of the message is shown, terminated by two periods. When the user drags down
on the notification, it expands to reveal the entire notification message:
This expanded layout format also includes summary text at the bottom of the notification. The maximum height
of the Big Text notification is 256 dp.
To create a Big Text notification, you instantiate a Notification.Builder object, as before, and then instantiate
and add a BigTextStyle object to the Notification.Builder object. For example:
In this example, the message text and summary text are stored in the BigTextStyle object ( textStyle ) before it
is passed to Notification.Builder.
Image Style
The Image style (also called the Big Picture style) is an expanded notification format that you can use to display
an image in the body of a notification. For example, a screenshot app or a photo app can use the Image
notification style to provide the user with a notification of the last image that was captured. Note that the
maximum height of the Image notification is 256 dp – Android will resize the image to fit into this maximum
height restriction, within the limits of available memory.
Like all expanded layout notifications, Image notifications are first displayed in a compact format that displays an
excerpt of the accompanying message text:
When the user drags down on the Image notification, it expands to reveal an image. For example, here is the
expanded version of the previous notification:
Notice that when the notification is displayed in compact format, it displays notification text (the text that is
passed to the notification builder's SetContentText method, as shown earlier). However, when the notification is
expanded to reveal the image, it displays summary text above the image.
To create an Image notification, you instantiate a Notification.Builder object as before, and then create and
insert a BigPictureStyle object into the Notification.Builder object. For example:
// Set the summary text that will appear with the image:
picStyle.SetSummaryText ("The summary text goes here.");
Like the SetLargeIcon method of Notification.Builder , the BigPicture method of BigPictureStyle requires a
bitmap of the image that you want to display in the body of the notification. In this example, the DecodeResource
method of BitmapFactory reads the image file located at Resources/drawable/x_bldg.png and converts it into
a bitmap.
You can also display images that are not packaged as a resource. For example, the following sample code loads
an image from the local SD card and displays it in an Image notification:
// Using the Image (Big Picture) style:
Notification.BigPictureStyle picStyle = new Notification.BigPictureStyle();
// Set the summary text that will appear with the image:
picStyle.SetSummaryText ("Check out my new T-Shirt!");
In this example, the image file located at /sdcard/Pictures/my-tshirt.jpg is loaded, resized to half of its original
size, and then converted to a bitmap for use in the notification:
If you don't know the size of the image file in advance, it's a good idea to wrap the call to
BitmapFactory.DecodeFile in an exception handler – an OutOfMemoryError exception might be thrown if the
image is too large for Android to resize.
For more about loading and decoding large bitmap images, see Load Large Bitmaps Efficiently.
Inbox Style
The Inbox format is an expanded layout template intended for displaying separate lines of text (such as an email
inbox summary) in the body of the notification. The Inbox format notification is first displayed in a compact
format:
When the user drags down on the notification, it expands to reveal an email summary as seen in the screenshot
below:
To create an Inbox notification, you instantiate a Notification.Builder object, as before, and add an InboxStyle
object to the Notification.Builder . For example:
To add new lines of text to the notification body, call the Addline method of the InboxStyle object (the maximum
height of the Inbox notification is 256 dp). Note that, unlike Big Text style, the Inbox style supports individual
lines of text in the notification body.
You can also use the Inbox style for any notification that needs to display individual lines of text in an expanded
format. For example, the Inbox notification style can be used to combine multiple pending notifications into a
summary notification – you can update a single Inbox style notification with new lines of notification content (see
Updating a Notification above), rather than generate a continuous stream of new, mostly similar notifications.
For more information about this approach, see Summarize your notifications.
Configuring Metadata
Notification.Builder includes methods that you can call to set metadata about your notification, such as
priority, visibility, and category. Android uses this information — along with user preference settings — to
determine how and when to display notifications.
Priority Settings
The priority setting of a notification determines two outcomes when the notification is published:
Where the notification appears in relation to other notifications. For example, high priority notifications
are presented above lower priority notifications in the notifications drawer, regardless of when each
notification was published.
Whether the notification is displayed in the Heads-up notification format (Android 5.0 and later). Only
high and maximum priority notifications are displayed as Heads-up notifications.
Xamarin.Android defines the following enumerations for setting notification priority:
NotificationPriority.Max – Alerts the user to an urgent or critical condition (for example, an incoming
call, turn-by-turn directions, or an emergency alert). On Android 5.0 and later devices, maximum priority
notifications are displayed in Heads-up format.
NotificationPriority.High – Informs the user of important events (such as important emails or the
arrival of real-time chat messages). On Android 5.0 and later devices, high priority notifications are
displayed in Heads-up format.
NotificationPriority.Default – Notifies the user of conditions that have a medium level of importance.
NotificationPriority.Low– For non-urgent information that the user needs to be informed of (for
example, software update reminders or social network updates).
NotificationPriority.Min – For background information that the user notices only when viewing
notifications (for example, location or weather information).
To set the priority of a notification, call the SetPriority method of the Notification.Builder object, passing in the
priority level. For example:
builder.SetPriority (NotificationPriority.High);
In the following example, the high priority notification, "An important message!" appears at the top of the
notification drawer:
Because this is a high-priority notification, it is also displayed as a Heads-up notification above the user's current
activity screen in Android 5.0:
In the next example, the low -priority "Thought for the day" notification is displayed under a higher-priority
battery level notification:
Because the "Thought for the day" notification is a low -priority notification, Android will not display it in Heads-
up format.
Visibility Settings
Beginning with Android 5.0, the visibility setting is available to control how much notification content appears on
the secure lockscreen. Xamarin.Android defines the following enumerations for setting notification visibility:
NotificationVisibility.Public – The full content of the notification is displayed on the secure lockscreen.
NotificationVisibility.Private – Only essential information is displayed on the secure lockscreen (such
as the notification icon and the name of the app that posted it), but the rest of the notification's details are
hidden. All notifications default to NotificationVisibility.Private .
NotificationVisibility.Secret – Nothing is displayed on the secure lockscreen, not even the notification
icon. The notification content is available only after the user unlocks the device.
To set the visibility of a notification, apps call the SetVisibility method of the Notification.Builder object,
passing in the visibility setting. For example, this call to SetVisibility makes the notification Private :
builder.SetVisibility (NotificationVisibility.Private);
When a Private notification is posted, only the name and icon of the app is displayed on the secure lockscreen.
Instead of the notification message, the user sees "Unlock your device to see this notification":
In this example, NotificationsLab is the name of the originating app. This redacted version of the notification
appears only when the lockscreen is secure (i.e., secured via PIN, pattern, or password) – if the lockscreen is not
secure, the full content of the notification is available on the lockscreen.
Category Settings
Beginning with Android 5.0, predefined categories are available for ranking and filtering notifications.
Xamarin.Android provides the following enumerations for these categories:
Notification.CategoryCall – Incoming phone call.
Notification.CategoryMessage – Incoming text message.
Notification.CategoryAlarm – An alarm condition or timer expiration.
Notification.CategoryEmail – Incoming email message.
Notification.CategoryEvent – A calendar event.
Notification.CategoryPromo – A promotional message or advertisement.
Notification.CategoryProgress – The progress of a background operation.
Notification.CategorySocial – Social networking update.
Notification.CategoryError – Failure of a background operation or authentication process.
Notification.CategoryTransport – Media playback update.
Notification.CategorySystem – Reserved for system use (system or device status).
Notification.CategoryService – Indicates that a background service is running.
Notification.CategoryRecommendation – A recommendation message related to the currently running app.
Notification.CategoryStatus – Information about the device.
When notifications are sorted, the notification's priority takes precedence over its category setting. For example,
a high-priority notification will be displayed as Heads-up even if it belongs to the Promo category. To set the
category of a notification, you call the SetCategory method of the Notification.Builder object, passing in the
category setting. For example:
builder.SetCategory (Notification.CategoryCall);
The Do not disturb feature (new in Android 5.0) filters notifications based on categories. For example, the Do not
disturb screen in Settings allows the user to exempt notifications for phone calls and messages:
When the user configures Do not disturb to block all interrupts except for phone calls (as illustrated in the above
screenshot), Android allows notifications with a category setting of Notification.CategoryCall to be presented
while the device is in Do not disturb mode. Note that Notification.CategoryAlarm notifications are never blocked
in Do not disturb mode.
Compatibility
If you are creating an app that will also run on earlier versions of Android (as early as API level 4), you use the
NotificationCompat.Builder class instead of Notification.Builder . When you create notifications with
NotificationCompat.Builder , Android ensures that basic notification content is displayed properly on older
devices. However, because some advanced notification features are not available on older versions of Android,
your code must explicitly handle compatibility issues for expanded notification styles, categories, and visibility
levels as explained below.
To use NotificationCompat.Builder in your app, you must include the Android Support Library v4 NuGet in your
project.
The following code sample illustrates how to create a basic notification using NotificationCompat.Builder :
As this example illustrates, method calls for essential notification options are identical to those of
Notification.Builder . However, your code has to handle downward-compatibility issues for more complex
notifications (described in the next section).
The LocalNotifications sample demonstrates how to use NotificationCompat.Builder to launch a second activity
from a notification. This sample code is explained in the Using Local Notifications in Xamarin.Android
walkthrough.
Notification Styles
To create Big Text, Image, or Inbox style notifications with NotificationCompat.Builder , your app must use the
compatibility versions of these styles. For example, to use the Big Text style, instantiate
NotificationCompat.BigTextstyle :
Similarly, your app can use NotificationCompat.InboxStyle and NotificationCompat.BigPictureStyle for Inbox
and Image styles, respectively.
Notification Priority and Category
NotificationCompat.Builder supports the SetPriority method (available starting with Android 4.1 ). However,
the SetCategory method is not supported by NotificationCompat.Builder because categories are part of the new
notification metadata system that was introduced in Android 5.0.
To support older versions of Android, where SetCategory is not available, your code can check the API level at
runtime to conditionally call SetCategory when the API level is equal to or greater than Android 5.0 (API level
21):
In this example, the app's Target Framework is set to Android 5.0 and the Minimum Android Version is set to
Android 4.1 (API Level 16). Because SetCategory is available in API level 21 and later, this example code will
call SetCategory only when it is available – it will not call SetCategory when the API level is less than 21.
Lockscreen Visibility
Because Android did not support lockscreen notifications before Android 5.0 (API level 21),
NotificationCompat.Builder does not support the SetVisibility method. As explained above for SetCategory ,
your code can check the API level at runtime and call SetVisiblity only when it is available:
Summary
This article explained how to create local notifications in Android. It described the anatomy of a notification, it
explained how to use Notification.Builder to create notifications, how to style notifications in large icon, Big
Text, Image and Inbox formats, how to set notification metadata settings such as priority, visibility, and category,
and how to launch an activity from a notification. This article also described how these notification settings work
with the new Heads-up, lockscreen, and Do not disturb features introduced in Android 5.0. Finally, you learned
how to use NotificationCompat.Builder to maintain notification compatibility with earlier versions of Android.
For guidelines about designing notifications for Android, see Notifications.
Related Links
NotificationsLab (sample)
LocalNotifications (sample)
Local Notifications In Android Walkthrough
Notifications
Notifying the User
Notification
NotificationManager
NotificationCompat.Builder
PendingIntent
Walkthrough - Using Local Notifications in
Xamarin.Android
4/12/2018 • 4 minutes to read • Edit Online
This walkthrough demonstrates how to use local notifications in Xamarin.Android applications. It demonstrates
the basics of creating and publishing a local notification. When the user clicks the notification in the notification
area, it starts up a second Activity.
Overview
In this walkthrough, we will create an Android application that raises a notification when the user clicks a button in
an Activity. When the user clicks the notification, it launches a second activity that displays the number of times the
user had clicked the button in the first Activity.
The following screenshots illustrate some examples of this application:
Walkthrough
To begin, let's create a new Android project using the Android App template. Let's call this project
LocalNotifications. (If you are not familiar with creating Xamarin.Android projects, see Hello, Android.)
Add the Android.Support.V4.App Component
In this walkthrough we are using NotificationCompat.Builder to build our local notification. As explained in Local
Notifications, we must include the Android Support Library v4 NuGet in our project to use
NotificationCompat.Builder .
Next, let's edit MainActivity.cs and add the following using statement so that the types in
Android.Support.V4.App are available to our code:
using Android.Support.V4.App;
Also, we must make it clear to the compiler that we are using the Android.Support.V4.App version of
TaskStackBuilder rather than the Android.App version. Add the following using statement to resolve any
ambiguity:
using TaskStackBuilder = Android.Support.V4.App.TaskStackBuilder;
// When the user clicks the notification, SecondActivity will start up.
Intent resultIntent = new Intent(this, typeof (SecondActivity));
In the OnCreate method, assign this ButtonOnClick method to the Click event of the button (replace the
delegate event handler provided by the template):
button.Click += ButtonOnClick;
using System;
using Android.App;
using Android.OS;
using Android.Widget;
namespace LocalNotifications
{
[Activity(Label = "Second Activity")]
public class SecondActivity : Activity
{
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
We must also create a resource layout for SecondActivity. Add a new Android Layout file to your project called
Second.axml. Edit Second.axml and paste in the following layout code:
If you swipe down and expose the notification drawer, you should see the notification:
When you click the notification, it should disappear, and our other activity should be launched – looking something
like the following screenshot:
Congratulations! At this point you have completed the Android local notification walkthrough and you have a
working sample that you can refer to. There is a lot more to notifications than we have shown here, so if you want
more information, take a look at Google's documentation on notifications and the Android Notifications design
guide.
Summary
In this walkthrough we used NotificationCompat.Builder to create and display notifications. We saw a basic
example of how to start up a second Activity as a way to respond to user interaction with the notification, and we
demonstrated the transfer of data from the first Activity to the second Activity.
Related Links
LocalNotifications (sample)
Design Guide Patterns on Notifications
Notification
NotificationManager
NotificationCompat.Builder
PendingIntent
Touch and Gestures in Xamarin.Android
5/2/2018 • 2 minutes to read • Edit Online
Touch screens on many of today's devices allow users to quickly and efficiently interact with devices in a natural
and intuitive way. This interaction is not limited just to simple touch detection - it is possible to use gestures as well.
For example, the pinch-to -zoom gesture is a very common example of this by pinching a part of the screen with
two fingers the user can zoom in or out. This guide examines touch and gestures in Android.
Touch Overview
iOS and Android are similar in the ways they handle touch. Both can support multi-touch - many points of contact
on the screen - and complex gestures. This guide introduces some of the similarities in concepts, as well as the
particularities of implementing touch and gestures on both platforms.
Android uses a MotionEvent object to encapsulate touch data, and methods on the View object to listen for
touches.
In addition to capturing touch data, both iOS and Android provide means for interpreting patterns of touches into
gestures. These gesture recognizers can in turn be used to interpret application-specific commands, such as a
rotation of an image or a turn of a page. Android provides a handful of supported gestures, as well as resources to
make adding complex custom gestures easy.
Whether you are working on Android or iOS, the choice between touches and gesture recognizers can be a
confusing one. This guide recommends that in general, preference should be given to gesture recognizers. Gesture
recognizers are implemented as discrete classes, which provide greater separation of concerns and better
encapsulation. This makes it easy to share the logic between different views, minimizing the amount of code
written.
This guide follows a similar format for each operating system: first, the platform’s touch APIs are introduced and
explained, as they are the foundation on which touch interactions are built. Then, we dive into the world of gesture
recognizers – first by exploring some common gestures, and finishing up with creating custom gestures for
applications. Finally, you'll see how to track individual fingers using low -level touch tracking to create a finger-paint
program.
Sections
Touch in Android
Walkthrough: Using Touch in Android
Multi-Touch tracking
Summary
In this guide we examined touch in Android. For both operating systems, we learned how to enable touch and how
to respond to the touch events. Next, we learned about gestures and some of the gesture recognizers that both
Android and iOS provide to handle some of the more common scenarios. We examined how to create custom
gestures and implement them in applications. A walkthrough demonstrated the concepts and APIs for each
operating system in action, and you also saw how to track individual fingers.
Related Links
Android Touch Start (sample)
Android Touch Final (sample)
FingerPaint (sample)
Touch in Android
4/12/2018 • 6 minutes to read • Edit Online
Much like iOS, Android creates an object that holds data about the user's physical interaction with the screen – an
Android.View.MotionEvent object. This object holds data such as what action is performed, where the touch took
place, how much pressure was applied, etc. A MotionEvent object breaks down the movement into to the following
values:
An action code that describes the type of motion, such as the initial touch, the touch moving across the
screen, or the touch ending.
A set of axis values that describe the position of the MotionEvent and other movement properties such as
where the touch is taking place, when the touch took place, and how much pressure was used. The axis
values may be different depending on the device, so the previous list does not describe all axis values.
The MotionEvent object will be passed to an appropriate method in an application. There are three ways for a
Xamarin.Android application to respond to a touch event:
Assign an event handler to View.Touch - The Android.Views.View class has an
EventHandler<View.TouchEventArgs> which applications can assign a handler to. This is typical .NET behavior.
Implementing View.IOnTouchListener - Instances of this interface may be assigned to a view object using
the View. SetOnListener method.This is functionally equivalent to assigning an event handler to the
View.Touch event. If there is some common or shared logic that many different views may need when they
are touched, it will be more efficient to create a class and implement this method than to assign each view its
own event handler.
Override View.OnTouchEvent - All views in Android subclass Android.Views.View . When a View is touched,
Android will call the OnTouchEvent and pass it a MotionEvent object as a parameter.
NOTE
Not all Android devices support touch screens.
Adding the following tag to your manifest file causes Google Play to only display your app to those devices that are
touch enabled:
Gestures
A gesture is a hand-drawn shape on the touch screen. A gesture can have one or more strokes to it, each stroke
consisting of a sequence of points created by a different point of contact with the screen. Android can support
many different types of gestures, from a simple fling across the screen to complex gestures that involve multi-
touch.
Android provides the Android.Gestures namespace specifically for managing and responding to gestures. At the
heart of all gestures is a special class called Android.Gestures.GestureDetector . As the name implies, this class will
listen for gestures and events based on MotionEvents supplied by the operating system.
To implement a gesture detector, an Activity must instantiate a GestureDetector class and provide an instance of
IOnGestureListener , as illustrated by the following code snippet:
An Activity must also implement the OnTouchEvent and pass the MotionEvent to the gesture detector. The
following code snippet shows an example of this:
When an instance of GestureDetector identifies a gesture of interest, it will notify the activity or application either
by raising an event or through a callback provided by GestureDetector.IOnGestureListener . This interface provides
six methods for the various gestures:
OnDown - Called when a tap occurs but is not released.
OnFling - Called when a fling occurs and provides data on the start and end touch that triggered the event.
OnLongPress - Called when a long press occurs.
OnScroll - Called when a scroll event occurs.
OnShowPress - Called after an OnDown has occurred and a move or up event has not been performed.
OnSingleTapUp - Called when a single tap occurs.
In many cases applications may only be interested in a subset of gestures. In this case, applications should extend
the class GestureDetector.SimpleOnGestureListener and override the methods that correspond to the events that
that they are interested in.
Custom Gestures
Gestures are a great way for users to interact with an application. The APIs we have seen so far would suffice for
simple gestures, but might prove a bit onerous for more complicated gestures. To help with more complicated
gestures, Android provides another set of API's in the Android.Gestures namespace that will ease some of the
burden associated with custom gestures.
Creating Custom Gestures
Since Android 1.6, the Android SDK comes with an application pre-installed on the emulator called Gestures
Builder. This application allows a developer to create pre-defined gestures that can be embedded in an application.
The following screen shot shows an example of Gestures Builder:
An improved version of this application called Gesture Tool can be found Google Play. Gesture Tool is very much
like Gestures Builder except that it allows you to test gestures after they have been created. This next screenshot
shows Gestures Builder:
Gesture Tool is a bit more useful for creating custom gestures as it allows the gestures to be tested as they are
being created and is easily available through Google Play.
Gesture Tool allows you create a gesture by drawing on the screen and assigning a name. After the gestures are
created they are saved in a binary file on the SD card of your device. This file needs to be retrieved from the device,
and then packaged with an application in the folder /Resources/raw. This file can be retrieved from the emulator
using the Android Debug Bridge. The following example shows copying the file from a Galaxy Nexus to the
Resource directory of an application:
Once you have retrieved the file it must be packaged with your application inside the directory /Resources/raw. The
easiest way to use this gesture file is to load the file into a GestureLibrary, as shown in the following snippet:
<android.gesture.GestureOverlayView
android:id="@+id/gestures"
android:layout_width="match_parent "
android:layout_height="match_parent" />
The GestureOverlayView has several events that will be raised during the process of drawing a gesture. The most
interesting event is GesturePeformed . This event is raised when the user has completed drawing their gesture.
When this event is raised, the Activity asks a GestureLibrary to try and match the gesture that the user with one of
the gestures created by Gesture Tool. GestureLibrary will return a list of Prediction objects.
Each Prediction object holds a score and name of one of the gestures in the GestureLibrary . The higher the score,
the more likely the gesture named in the Prediction matches the gesture drawn by the user. Generally speaking,
scores lower than 1.0 are considered poor matches.
The following code shows an example of matching a gesture:
private void GestureOverlayViewOnGesturePerformed(object sender, GestureOverlayView.GesturePerformedEventArgs
gesturePerformedEventArgs)
{
// In this example _gestureLibrary was instantiated in OnCreate
IEnumerable<Prediction> predictions = from p in _gestureLibrary.Recognize(gesturePerformedEventArgs.Gesture)
orderby p.Score descending
where p.Score > 1.0
select p;
Prediction prediction = predictions.FirstOrDefault();
if (prediction == null)
{
Log.Debug(GetType().FullName, "Nothing matched the user's gesture.");
return;
}
With this done, you should have an understanding of how to use touch and gestures in a Xamarin.Android
application. Let us now move on to a walkthrough and see all of the concepts in a working sample application.
Related Links
Android Touch Start (sample)
Android Touch Final (sample)
Walkthrough - Using Touch in Android
7/9/2018 • 8 minutes to read • Edit Online
Let us see how to use the concepts from the previous section in a working application. We will create an
application with four activities. The first activity will be a menu or a switchboard that will launch the other activities
to demonstrate the various APIs. The following screenshot shows the main activity:
The first Activity, Touch Sample, will show how to use event handlers for touching the Views. The Gesture
Recognizer activity will demonstrate how to subclass Android.View.Views and handle events as well as show how
to handle pinch gestures. The third and final activity, Custom Gesture, will show how use custom gestures. To
make things easier to follow and absorb, we'll break this walkthrough up into sections, with each section focusing
on one of the Activities.
_touchMeImageView.Touch += TouchMeImageViewOnTouch;
case MotionEventActions.Up:
message = "Touch Ends";
break;
default:
message = string.Empty;
break;
}
_touchInfoTextView.Text = message;
}
Notice in the code above that we treat the Move and Down action as the same. This is because even though the
user may not lift their finger off the ImageView , it may move around or the pressure exerted by the user may
change. These types of changes will generate a Move action.
Each time the user touches the ImageView , the Touch event will be raised and our handler will display the
message Touch Begins on the screen, as shown in the following screenshot:
As long as the user is touching the ImageView , Touch Begins will be displayed in the TextView . When the user is
no longer touching the ImageView , the message Touch Ends will be displayed in the TextView , as shown in the
following screenshot:
Gesture Recognizer Activity
Now lets implement the Gesture Recognizer activity. This activity will demonstrate how to drag a view around the
screen and illustrate one way to implement pinch-to-zoom.
Add a new Activity to the application called GestureRecognizer . Edit the code for this activity so that it
resembles the following code:
Add a new Android view to the project, and name it GestureRecognizerView . Add the following variables to
this class:
private static readonly int InvalidPointerId = -1;
Add the following constructor to GestureRecognizerView . This constructor will add an ImageView to our
activity. At this point the code still will not compile – we need to create the class MyScaleListener that will
help with resizing the ImageView when the user pinches it:
To draw the image on our activity, we need to override the OnDraw method of the View class as shown in
the following snippet. This code will move the ImageView to the position specified by _posX and _posY as
well as resize the image according to the scaling factor:
Next we need to update the instance variable _scaleFactor as the user pinches the ImageView . We will add
a class called MyScaleListener . This class will listen for the scale events that will be raised by Android when
the user pinches the ImageView . Add the following inner class to GestureRecognizerView . This class is a
ScaleGesture.SimpleOnScaleGestureListener . This class is a convenience class that listeners can subclass
when you are interested in a subset of gestures:
private class MyScaleListener : ScaleGestureDetector.SimpleOnScaleGestureListener
{
private readonly GestureRecognizerView _view;
_view.Invalidate();
return true;
}
}
The next method we need to override in GestureRecognizerView is OnTouchEvent . The following code lists
the full implementation of this method. There is a lot of code here, so lets take a minute and look what is
going on here. The first thing this method does is scale the icon if necessary – this is handled by calling
_scaleDetector.OnTouchEvent . Next we try to figure out what action called this method:
If the user touched the screen with, we record the X and Y positions and the ID of the first pointer
that touched the screen.
If the user moved their touch on the screen, then we figure out how far the user moved the pointer.
If the user has lifted his finger off the screen, then we will stop tracking the gestures.
public override bool OnTouchEvent(MotionEvent ev)
{
_scaleDetector.OnTouchEvent(ev);
switch (action)
{
case MotionEventActions.Down:
_lastTouchX = ev.GetX();
_lastTouchY = ev.GetY();
_activePointerId = ev.GetPointerId(0);
break;
case MotionEventActions.Move:
pointerIndex = ev.FindPointerIndex(_activePointerId);
float x = ev.GetX(pointerIndex);
float y = ev.GetY(pointerIndex);
if (!_scaleDetector.IsInProgress)
{
// Only move the ScaleGestureDetector isn't already processing a gesture.
float deltaX = x - _lastTouchX;
float deltaY = y - _lastTouchY;
_posX += deltaX;
_posY += deltaY;
Invalidate();
}
_lastTouchX = x;
_lastTouchY = y;
break;
case MotionEventActions.Up:
case MotionEventActions.Cancel:
// We no longer need to keep track of the active pointer.
_activePointerId = InvalidPointerId;
break;
case MotionEventActions.PointerUp:
// check to make sure that the pointer that went up is for the gesture we're tracking.
pointerIndex = (int) (ev.Action & MotionEventActions.PointerIndexMask) >> (int)
MotionEventActions.PointerIndexShift;
int pointerId = ev.GetPointerId(pointerIndex);
if (pointerId == _activePointerId)
{
// This was our active pointer going up. Choose a new
// action pointer and adjust accordingly
int newPointerIndex = pointerIndex == 0 ? 1 : 0;
_lastTouchX = ev.GetX(newPointerIndex);
_lastTouchY = ev.GetY(newPointerIndex);
_activePointerId = ev.GetPointerId(newPointerIndex);
}
break;
}
return true;
}
Now run the application, and start the Gesture Recognizer activity. When it starts the screen should look
something like the screenshot below:
Now touch the icon, and drag it around the screen. Try the pinch-to-zoom gesture. At some point your
screen may look something like the following screen shot:
At this point you should give yourself a pat on the back: you have just implemented pinch-to-zoom in an Android
application! Take a quick break and lets move on to the third and final Activity in this walkthrough – using custom
gestures.
Custom Gesture Activity
The final screen in this walkthrough will use custom gestures.
For the purposes of this Walkthrough, the gestures library has already been created using Gesture Tool and added
to the project in the file Resources/raw/gestures. With this bit of housekeeping out of the way, lets get on with
the final Activity in the walkthrough.
Add a layout file named custom_gesture_layout.axml to the project with the following contents. The
project already has all the images in the Resources folder:
Next add a new Activity to the project and name it CustomGestureRecognizerActivity.cs . Add two instance
variables to the class, as showing in the following two lines of code:
Edit the OnCreate method of the this Activity so that it resembles the following code. Lets take a minute to
explain what is going on in this code. The first thing we do is instantiate a GestureOverlayView and set that
as the root view of the Activity. We also assign an event handler to the GesturePerformed event of
GestureOverlayView . Next we inflate the layout file that was created earlier, and add that as a child view of
the GestureOverlayView . The final step is to initialize the variable _gestureLibrary and load the gestures file
from the application resources. If the gestures file cannot be loaded for some reason, there is not much this
Activity can do, so it is shutdown:
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
The final thing we need to do implement the method GestureOverlayViewOnGesturePerformed as shown in the
following code snippet. When the GestureOverlayView detects a gesture, it calls back to this method. The
first thing we try to get an IList<Prediction> objects that match the gesture by calling
_gestureLibrary.Recognize() . We use a bit of LINQ to get the Prediction that has the highest score for the
gesture.
If there was no matching gesture with a high enough score, then the event handler exits without doing
anything. Otherwise we check the name of the prediction and change the image being displayed based on
the name of the gesture:
if (prediction == null)
{
Log.Debug(GetType().FullName, "Nothing seemed to match the user's gesture, so don't do
anything.");
return;
}
if (prediction.Name.StartsWith("checkmark"))
{
_imageView.SetImageResource(Resource.Drawable.checked_me);
}
else if (prediction.Name.StartsWith("erase", StringComparison.OrdinalIgnoreCase))
{
// Match one of our "erase" gestures
_imageView.SetImageResource(Resource.Drawable.check_me);
}
}
Run the application and start up the Custom Gesture Recognizer activity. It should look something like the
following screenshot:
Now draw a checkmark on the screen, and the bitmap being displayed should look something like that
shown in the next screenshots:
Finally, draw a scribble on the screen. The checkbox should change back to its original image as shown in
these screenshots:
You now have an understanding of how to integrate touch and gestures in an Android application using
Xamarin.Android.
Related Links
Android Touch Start (sample)
Android Touch Final (sample)
Multi-Touch Finger Tracking
5/2/2018 • 5 minutes to read • Edit Online
This topic demonstrates how to track touch events from multiple fingers
There are times when a multi-touch application needs to track individual fingers as they move simultaneously on
the screen. One typical application is a finger-paint program. You want the user to be able to draw with a single
finger, but also to draw with multiple fingers at once. As your program processes multiple touch events, it needs to
distinguish which events correspond to each finger. Android supplies an ID code for this purpose, but obtaining
and handling that code can be a little tricky.
For all the events associated with a particular finger, the ID code remains the same. The ID code is assigned when a
finger first touches the screen, and becomes invalid after the finger lifts from the screen. These ID codes are
generally very small integers, and Android reuses them for later touch events.
Almost always, a program that tracks individual fingers maintains a dictionary for touch tracking. The dictionary
key is the ID code that identifies a particular finger. The dictionary value depends on the application. In the
FingerPaint program, each finger stroke (from touch to release) is associated with an object that contains all the
information necessary to render the line drawn with that finger. The program defines a small FingerPaintPolyline
class for this purpose:
class FingerPaintPolyline
{
public FingerPaintPolyline()
{
Path = new Path();
}
Each polyline has a color, a stroke width, and an Android graphics Path object to accumulate and render multiple
points of the line as it's being drawn.
The remainder of the code shown below is contained in a View derivative named FingerPaintCanvasView . That
class maintains a dictionary of objects of type FingerPaintPolyline during the time that they are actively being
drawn by one or more fingers:
This dictionary allows the view to quickly obtain the FingerPaintPolyline information associated with a particular
finger.
The FingerPaintCanvasView class also maintains a List object for the polylines that have been completed:
The objects in this List are in the same order that they were drawn.
FingerPaintCanvasView overrides two methods defined by View : OnDraw and OnTouchEvent . In its OnDraw
override, the view draws the completed polylines and then draws the in-progress polylines.
The override of the OnTouchEvent method begins by obtaining a pointerIndex value from the ActionIndex
property. This ActionIndex value differentiates between multiple fingers, but it is not consistent across multiple
events. For that reason, you use the pointerIndex to obtain the pointer id value from the GetPointerId method.
This ID is consistent across multiple events:
// Use ActionMasked here rather than Action to reduce the number of possibilities
switch (args.ActionMasked)
{
// ...
}
Notice that the override uses the ActionMasked property in the switch statement rather than the Action
property. Here's why:
When you're dealing with multi-touch, the Action property has a value of MotionEventsAction.Down for the first
finger to touch the screen, and then values of Pointer2Down and Pointer3Down as the second and third fingers also
touch the screen. As the fourth and fifth fingers make contact, the Action property has numeric values that don't
even correspond to members of the MotionEventsAction enumeration! You'd need to examine the values of bit
flags in the values to interpret what they mean.
Similarly, as the fingers leave contact with the screen, the Action property has values of Pointer2Up and
Pointer3Up for the second and third fingers, and Up for the first finger.
The ActionMasked property takes on a fewer number of values because it's intended to be used in conjunction with
the ActionIndex property to differentiate between multiple fingers. When fingers touch the screen, the property
can only equal MotionEventActions.Down for the first finger and PointerDown for subsequent fingers. As the fingers
leave the screen, ActionMasked has values of Pointer1Up for the subsequent fingers and Up for the first finger.
When using ActionMasked , the ActionIndex distinguishes among the subsequent fingers to touch and leave the
screen, but you usually don't need to use that value except as an argument to other methods in the MotionEvent
object. For multi-touch, one of the most important of these methods is GetPointerId called in the code above. That
method returns a value that you can use for a dictionary key to associate particular events to fingers.
The OnTouchEvent override in the FingerPaint program processes the MotionEventActions.Down and PointerDown
events identically by creating a new FingerPaintPolyline object and adding it to the dictionary:
public override bool OnTouchEvent(MotionEvent args)
{
// Get the pointer index
int pointerIndex = args.ActionIndex;
// Use ActionMasked here rather than Action to reduce the number of possibilities
switch (args.ActionMasked)
{
case MotionEventActions.Down:
case MotionEventActions.PointerDown:
polyline.Path.MoveTo(args.GetX(pointerIndex),
args.GetY(pointerIndex));
inProgressPolylines.Add(id, polyline);
break;
// ...
}
// ...
}
Notice that the pointerIndex is also used to obtain the position of the finger within the view. All the touch
information is associated with the pointerIndex value. The id uniquely identifies fingers across multiple
messages, so that's used to create the dictionary entry.
Similarly, the OnTouchEvent override also handles the MotionEventActions.Up and Pointer1Up identically by
transferring the completed polyline to the completedPolylines collection so they can be drawn during the OnDraw
override. The code also removes the id entry from the dictionary:
inProgressPolylines[id].Path.LineTo(args.GetX(pointerIndex),
args.GetY(pointerIndex));
case MotionEventActions.Cancel:
inProgressPolylines.Remove(id);
break;
}
// ...
}
Now for the tricky part.
Between the down and up events, generally there are many MotionEventActions.Move events. These are bundled in
a single call to OnTouchEvent , and they must be handled differently from the Down and Up events. The
pointerIndex value obtained earlier from the ActionIndex property must be ignored. Instead, the method must
obtain multiple pointerIndex values by looping between 0 and the PointerCount property, and then obtain an id
for each of those pointerIndex values:
inProgressPolylines[id].Path.LineTo(args.GetX(pointerIndex),
args.GetY(pointerIndex));
}
break;
// ...
}
// ...
}
This type of processing allows the FingerPaint program to track individual fingers and draw the results on the
screen:
You've now seen how you can track individual fingers on the screen and distinguish among them.
Related Links
Equivalent Xamarin iOS guide
FingerPaint (sample)
HttpClient Stack and SSL/TLS Implementation
Selector for Android
5/31/2018 • 4 minutes to read • Edit Online
The HttpClient Stack and SSL/TLS Implementation selectors determine the HttpClient and SSL/TLS
implementation that will be used by your Xamarin.Android apps.
Projects must reference the System.Net.Http assembly.
WARNING
April, 2018 – Due to increased security requirements, including PCI compliance, major cloud providers and web servers are
expected to stop supporting TLS versions older than 1.2. Xamarin projects created in previous versions of Visual Studio
default to use older versions of TLS.
In order to ensure your apps continue to work with these servers and services, you should update your Xamarin projects
with the Android HttpClient and Native TLS 1.2 settings shown below, then re-build and re-deploy your apps
to your users.
Visual Studio
Visual Studio for Mac
The Xamarin.Android HttpClient configuration is in Project Options > Android Options, then click the
Advanced Options button.
These are the recommended settings for TLS 1.2 support:
NOTE
The underlying Android device must support TLS 1.2 (ie. Android 5.0 and later)
Visual Studio
Visual Studio for Mac
For example:
If the HttpClient implementation was set to Managed and the TLS implementation was set to Native TLS 1.2+,
then the client object would automatically use the managed HttpClientHandler and TLS 1.2 (provided by the
BoringSSL library) for its HTTP requests.
However, if the HttpClient implementation is set to AndroidHttpClient , then all HttpClient objects will use the
underlying Java class java.net.URLConnection and will be unaffected by the TLS/SSL implementation value.
WebRequest objects would use the BoringSSL library.
XA_HTTP_CLIENT_HANDLER_TYPE=Xamarin.Android.Net.AndroidClientHandler
XA_TLS_PROVIDER – This environment variable will declare which TLS library will be used, either btls ,
legacy , or default (which is the same as omitting this variable):
XA_TLS_PROVIDER=btls
This environment variable is set by adding an environment file to the project. An environment file is a Unix-
formatted plain-text file with a build action of AndroidEnvironment:
Visual Studio
Visual Studio for Mac
Please see the Xamarin.Android Environment guide for more details about environment variables and
Xamarin.Android.
Related Links
Transport Layer Security (TLS )
Writing Responsive Applications
4/12/2018 • 2 minutes to read • Edit Online
One of the keys to maintaining a responsive GUI is to do long-running tasks on a background thread so the GUI
doesn't get blocked. Let's say we want to calculate a value to display to the user, but that value takes 5 seconds to
calculate:
SetContentView (textview);
SlowMethod ();
}
This will work, but the application will "hang" for 5 seconds while the value is calculated. During this time, the app
will not respond to any user interaction. To get around this, we want to do our calculations on a background thread:
SetContentView (textview);
This is because you must update the GUI from the GUI thread. Our code updates the GUI from the ThreadPool
thread, causing the app to crash. We need to calculate our value on the background thread, but then do our update
on the GUI thread, which is handled with Activity.RunOnUIThread:
SetContentView (textview);
This code works as expected. This GUI stays responsive and gets properly updated once the calculation is comple.
Note this technique isn't just used for calculating an expensive value. It can be used for any long-running task that
can be done in the background, like a web service call or downloading internet data.
User Interface
5/2/2018 • 2 minutes to read • Edit Online
The following sections explain the various tools and building blocks that are used to compose user interfaces in
Xamarin.Android apps.
Android Designer
This section explains how to use the Android Designer to lay out controls visually and edit properties. It also
explains how to use the Designer to work with user interfaces and resources across various configurations, such as
themes, languages, and device configurations, as well as how to design for alternative views like landscape and
portrait.
Material Theme
Material Theme is the user interface style that determines the look and feel of views and activities in Android.
Material Theme is built into Android, so it is used by the system UI as well as by applications. This guide introduces
Material Design principles and explains how to theme an app using either built-in Material Themes or a custom
theme.
User Profile
This guide explains how to access the personal profile for the owner of a device, including contact data such as the
device owner's name and phone number.
Splash Screen
An Android app takes some time to to start up, especially when the app is first launched on a device. A splash
screen may display start up progress to the user. This guide explains how to create a splash screen for your app.
Layouts
Layouts are used to define the visual structure for a user interface. Layouts such as ListView and RecyclerView
are the most fundamental building blocks of Android applications. Typically, a layout will use an Adapter to act as a
bridge from the layout to the underlying data that is used to populate data items in the layout. This section explains
how to use layouts such as LinearLayout , RelativeLayout , TableLayout , RecyclerView , and GridView .
Controls
Android controls (also called widgets) are the UI elements that you use to build a user interface. This section
explains how to use controls such as buttons, toolbars, date/time pickers, calendars, spinners, switches, pop-up
menus, view pagers, and web views.
Android Designer
4/12/2018 • 2 minutes to read • Edit Online
This article covers the features of the Xamarin.Android Designer. It covers designer basics, showing how to use the
Designer to lay out widgets visually and how to edit properties. It also shows how to use the Designer to work with
user interfaces and resources across various configurations, such as themes, languages, and device configurations,
as well as how to design for alternative views like landscape and portrait.
Overview
Xamarin.Android supports both a declarative style of user interface design based in XML files, as well as
programmatic user interface creation in code. When using the declarative approach, XML files can be either hand-
edited or modified visually by using the Xamarin.Android Designer. Use of a designer allows immediate feedback
during UI creation, speeds up development, and makes the process of UI creation less laborious.
This article surveys the many features of the Xamarin.Android Designer. It explains:
1. The basics of using the Designer.
2. The various parts that make up the Designer.
3. How to load an Android layout into the Designer.
4. How to add widgets.
5. How to edit properties.
6. How to work with various resources and device configurations.
7. How to modify a user interface for alternative views such as landscape and portrait.
8. How to handle conflicts that may arise when working with alternative views.
9. How to use Material Design tools to build Material Design-compliant apps.
Sections
Using the Android Designer
Designer Basics
Resource Qualifiers and Visualization Options
Alternative Layout Views
Material Design Features
Summary
This article discussed the feature set of the Xamarin.Android Designer. It showed how to get started with the
Designer, and explained its various parts. It described how to load a layout, as well as how to add and modify
widgets, both by using the Property Pad and inline on the Designer surface. It also explained how to work with
various resources and device configurations. Finally, it examined how to use the Designer to develop user
interfaces that are built specifically for alternative views, such as landscape and portrait, as well as how to resolve
conflicts that may arise between such views.
Related Links
Designer Walkthrough
Android Resources
Using the Android Designer
5/7/2018 • 9 minutes to read • Edit Online
This topic is a walkthrough of the Xamarin.Android Designer. It demonstrates how to create a user interface for a
small color browser app; this user interface is created entirely in the Designer.
Overview
Android user interfaces can be created declaratively by using XML files or programmatically by writing code. The
Xamarin.Android Designer allows developers to create and modify declarative layouts visually, without having to
deal with the tedium of hand-editing XML files. The Designer also provides real-time feedback, which lets the
developer evaluate UI changes without having to redeploy the application to a device or to an emulator. This can
speed up Android UI development tremendously. In this article, we present a walkthrough that shows how to use
the Xamarin.Android Designer to visually create a user interface.
Walkthrough
The objective of this walkthrough is to use the Android Designer to create a user interface for an example color
browser app that presents a list of colors, their names, and their RGB values. We'll look at how to add widgets to
the Design Surface as well as how to lay out these widgets visually. After that, we'll explain how to modify widgets
interactively on the Design Surface or by using the Designer's Property Pad. Finally, we'll see how our design
looks when we run the app.
Let's get started!
Creating a New Project
The first step is to create a new Xamarin.Android project.
Visual Studio
Visual Studio for Mac
Launch Visual Studio and click New Project... then choose the Visual C# > Android > Android App (Xamarin)
template:
Visual Studio
Visual Studio for Mac
Name the new app DesignerWalkthrough and click OK.
Adding a Layout
Let's create a LinearLayout that we will use to hold our user interface elements.
Visual Studio
Visual Studio for Mac
In Visual Studio, right-click Resources/layout in the Solution Explorer and select Add > New Item.... In the
Add New Item dialog, select Android Layout. Name the file ListItem.axml and click Add:
Click the Source tab at the bottom of the Designer to view the XML source for this layout:
From the View menu, click Other Windows > Document Outline to open the Document Outline. The
Document Outline shows that the layout currently contains a single LinearLayout widget:
When you select the ImageView in the Designer, the blue outline moves to surround the ImageView ; in the
Document Outline, the selection moves to imageView1 (ImageView) :
Visual Studio
Visual Studio for Mac
Next, drag a Text (Large) widget from the Toolbox into the newly-added LinearLayout . Notice that the Designer
uses green highlights to indicate where the new widget will be inserted:
Visual Studio
Visual Studio for Mac
Next, add a Text (Small) widget below the Text (Large) widget:
Visual Studio
Visual Studio for Mac
Visual Studio
Visual Studio for Mac
1. Select the ImageView .
2. In the Properties window, click the Categorized sort icon and scroll down to the Layout - ViewGroup
section.
3. Change the layout_width setting to wrap_content :
Another way to change the Width setting is to click the triangle on the right-hand side of the widget to toggle its
width setting to wrap_content :
Visual Studio
Visual Studio for Mac
The bottom, left, right, and top padding settings can be set independently by entering values into the
paddingBottom , paddingLeft , paddingRight , and paddingTop fields, respectively. For example, set the paddingLeft
field to 5dp and the paddingBottom , paddingRight , and paddingTop fields to 10dp :
Visual Studio
Visual Studio for Mac
Next, tweak the position of the LinearLayout widget that contains the two TextView widgets. In the Document
Outline, select linearLayout1 . In the Properties window, scroll to the Layout - ViewGroup section. Set
layout_marginBottom , layout_marginLeft , layout_marginRight , and layout_marginTop to 5dp , 5dp , 0dp , and
5dp respectively:
Removing the Default Image
Because we're using the ImageView to display colors (rather than images), let's remove the default image source
added by the template.
Visual Studio
Visual Studio for Mac
1. Select the ImageView .
2. In Properties, find the src field.
3. Clear the src setting so that it is blank:
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using System.Collections.Generic;
namespace DesignerWalkthrough
{
[Activity (Label = "DesignerWalkthrough", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
List<ColorItem> colorItems = new List<ColorItem> ();
ListView listView;
SetContentView (Resource.Layout.Main);
listView = FindViewById<ListView> (Resource.Id.myListView);
return view;
}
}
This code uses a custom ListView adapter to load color information and display this data in the UI we've just
created. To keep this example short, the color information is hard-coded in a list, but the adapter could be modified
to extract color information from a data source or to calculate it on the fly. For more information about ListView
adapters, see ListViews and Adapters.
Build and run the application. The following screenshot is an example of how the app appears when running on a
device:
Summary
In this article, we walked through how to use the Xamarin.Android Designer in Visual Studio for Mac to create a
user interface. Next, we demonstrated how to create the interface for a single item in a list. Along the way, we
looked at how to add widgets and to lay them out visually, as well as how to assign resources and to set various
properties on those widgets. In conclusion, we illustrated how the interface we created in the Designer runs in an
example application.
Designer Basics
5/7/2018 • 12 minutes to read • Edit Online
This topic introduces Designer features, explains how to launch the Designer, describes the Design Surface, and
details how to use the Properties pane to edit widget properties.
Visual Studio
Visual Studio for Mac
Likewise, you can add a new layout by right-clicking the layout folder in the Solution Explorer and selecting Add
> New Item... > Android Layout:
This creates a new .axml file and loads it onto the Design Surface.
Designer Features
The Designer is composed of several sections that support its various features, as shown in the following
screenshot:
Visual Studio
Visual Studio for Mac
When you edit a layout in the Designer, you use the following features to create and shape your design:
Visual Studio
Visual Studio for Mac
Design Surface – Facilitates the visual construction of the user interface by giving you an editable
representation of how the layout will appear on the device.
Toolbar – Displays a list of selectors: Device, Version, Theme, layout configuration, and Action Bar
settings. The Toolbar also includes icons for launching the Theme Editor and for enabling the Material
Design Grid.
Toolbox – Provides a list of widgets and layouts that you can drag and drop onto the Design Surface.
Properties Window – Lists the properties of the selected widget for viewing and editing.
Document Outline – Displays the tree of widgets that compose the layout. You can click an item in the tree
to cause it to be selected in the Designer. Also, clicking an item in the tree loads the item's properties into
the Properties window.
Toolbar
The Toolbar (positioned above the Design Surface) presents configuration selectors and tool menus:
Visual Studio
Visual Studio for Mac
The Toolbar provides access to the following features:
Alternative Layout Selector – Allows you to select from different layout versions.
Device Selector – Defines a set of qualifiers associated with a particular device such as screen size,
resolution, and keyboard availability. You can also add and delete new devices.
Android Version Selector – The Android version that the layout is targeting. The Designer will render the
layout according to the selected Android version.
Theme Selector – Selects the UI theme for the layout.
Configuration Selector – Selects the device configuration, such as portrait or landscape.
Resource Qualifier Options – Opens a dialog that presents drop-down menus for selecting Language, UI
Mode, Night Mode, and Round Screen options.
Action Bar Settings – Configures the Action Bar settings for the layout.
Theme Editor – Opens the Theme Editor, which makes it possible for you to customize elements of the
selected theme.
Material Design Grid – Enables or disables the Material Design Grid. The drop-down menu item adjacent
to the Material Design Grid opens a dialog that enables you to customize the grid.
Each of these features is explained in more detail in these topics:
Resource Qualifiers and Visualization Options provides detailed information about the Device Selector, Android
Version Selector, Theme Selector, Configuration Selector, Resource Qualifications Options, and Action
Bar Settings.
Alternative Layout Views explains how to use the Alternative Layout Selector.
Material Design Features provides a comprehensive overview of the Theme Editor and the Material Design
Grid.
Design Surface
The Designer makes it possible for you to drag and drop widgets from the toolbox onto the Design Surface. When
you interact with widgets in the Designer (by either adding new widgets or repositioning existing ones), vertical
and horizontal lines are displayed to mark the available insertion points. In the following example, a new Button
widget is being dragged to the Design Surface:
Visual Studio
Visual Studio for Mac
Additionally, widgets can be copied: you can use copy and paste to copy a widget, or you can drag and drop an
existing widget while pressing the Ctrl key.
Context Menu Commands
A context menu is available both in the Design Surface and in the Document Outline. This menu displays
commands that are available for the selected widget and its container, making it easier for you to perform
operations on containers (which are not always easy to select on the Design Surface). Here is an example of a
context menu:
Visual Studio
Visual Studio for Mac
In this example, right-clicking a TextView opens a context menu that provides several options:
LinearLayout – opens a submenu for editing the LinearLayout parent of the TextView .
Delete, Copy, and Cut – operations that apply to the right-clicked TextView .
In this example, right-clicking a TextView opens a context menu that provides several options:
LinearLayout – opens a submenu for editing the LinearLayout parent of the TextView .
Delete, Copy, and Cut – operations that apply to the right-clicked TextView .
Zoom Controls
The Design Surface supports zooming via several controls as shown:
Visual Studio
Visual Studio for Mac
These controls make it easier to see certain areas of the user interface in the Designer:
Highlight Containers – Highlights containers on the Design Surface so that they are easier to locate while
zooming in and out.
Normal Size – Renders the layout pixel-for-pixel so that you can see how the layout will look at the
resolution of the selected device.
Fit to Window – Sets the zoom level so that the entire layout is visible on the Design Surface.
Zoom In – Zooms in incrementally with each click, magnifying the layout.
Zoom Out – Zooms out incrementally with each click, making the layout appear smaller on the Design
Surface.
Note that the chosen zoom setting does not affect the user interface of the application at runtime.
Visual Studio
Visual Studio for Mac
Visual Studio
Visual Studio for Mac
Properties Window
The Designer supports the editing of widget properties through the Properties Window. The properties listed in
the Properties window change depending on which widget is selected on the Design Surface. When the Button in
the previous example is selected, the properties for that Button widget are shown:
Default Values
Visual Studio
Visual Studio for Mac
The properties of most widgets will be blank in the Properties window because their values inherit from the
selected Android theme. The Properties window will only show values that are explicitly set for the selected
widget; it will not show values that are inherited from the theme.
Referencing Resources
Some properties can reference resources that are defined in files other than the layout .axml file. The most
common cases of this type are string and drawable resources. However, references can also be used for other
resources, such as Boolean values and dimensions. When a property supports resource references, a browse icon
(an ellipsis, …) is shown next to the text entry for the property. This button opens a resource selector when clicked.
Visual Studio
Visual Studio for Mac
For example, the following screenshot shows the resources available when clicking the ellipsis to the right of the
text field for a Button widget in the Properties window:
The next example illustrates the resource selector for the Src property of an ImageView :
Visual Studio
Visual Studio for Mac
You can enter a new text value or you can enter a new resource string. In the following example, the @string/hello
resource is being replaced with the text, CLICK THIS BUTTON :
Visual Studio
Visual Studio for Mac
This change is stored in the widget's text property; it does not modify the value assigned to the @string/hello
resource. When you key in a new text string, you can press Shift + Enter to automatically link the entered text to
a new resource.
Margin
When you select a widget, the Designer displays handles that allow you to change the size or margin of the widget
interactively. Clicking the widget while it is selected toggles between margin-editing mode and size-editing mode.
When you click a widget for the first time, margin handles are displayed. If you move the mouse to one of the
handles, the Designer displays the property that the handle will change (as shown below for the
layout_marginLeft property):
Visual Studio
Visual Studio for Mac
If a margin has already been set, dotted lines are displayed, indicating the space that the margin occupies:
Visual Studio
Visual Studio for Mac
Size
As mentioned earlier, you can switch to size-editing mode by clicking a widget while it is already selected. Click the
triangular handle to set the size for the indicated dimension to wrap_content :
Visual Studio
Visual Studio for Mac
Clicking the Wrap Content handle shrinks the widget in that dimension so that is no larger than necessary to
wrap the enclosed content. In this example, the button text shrinks horizontally as shown in the next screenshot.
When the size value is set to Wrap Content, the Designer displays a triangular handle pointing in the opposite
direction for changing the size to match_parent :
Visual Studio
Visual Studio for Mac
Clicking the Match Parent handle restores the size in that dimension so that it is the same as the parent widget.
Also, you can drag the circular resize handle (as shown in the above screenshots) to resize the widget to an
arbitrary dp value. When you do so, both Wrap Content and Match Parent handles are presented for that
dimension:
Visual Studio
Visual Studio for Mac
Not all containers allow editing the Size of a widget. For example, notice that in the screenshot below with the
LinearLayout selected, the resize handles do not appear:
Visual Studio
Visual Studio for Mac
Document Outline
The Document Outline displays the widget hierarchy of the layout. In the following example, the containing
LinearLayout widget is selected:
Visual Studio
Visual Studio for Mac
The outline of the selected widget (in this case, a LinearLayout ) is also highlighted on the Design Surface. The
selected widget in the Document Outline stays in sync with its counterpart on the Design Surface. This is useful for
selecting view groups, which are not always easy to select on the Design Surface.
The Document Outline supports copy and paste, or you can use drag and drop. Drag and drop is supported from
the Document Outline to the Design Surface as well as from the Design Surface to the Document Outline. Also,
right-clicking an item in the Document Outline displays the context menu for that item (the same context menu
that appears when you right-click that same widget on the Design Surface).
Resource Qualifiers and Visualization Options
7/3/2018 • 6 minutes to read • Edit Online
This topic explains how to define resources that will be used only when some qualifier values are matched. A
simple example is a language-qualified string resource. A string resource can be defined as the default, with other
alternative resources defined to be used for additional languages. All resource types can be qualified, including the
layout itself.
Selecting Customize displays a dialog that that you can use for browsing through available device configurations.
When you click the Device Definitions tab, a list of all known device definitions is presented:
Visual Studio
Visual Studio for Mac
Devices preconfigured in the Designer cannot be modified. However, you can click Create Device... to define a
custom device definition. Alternately, you can select an existing definition and click Clone... to use it as the starting
point for a new definition. For example, selecting the Nexus 5 definition and clicking Clone... presents the
following dialog:
Visual Studio
Visual Studio for Mac
In the next screenshot, the name is changed to Nexus 5 Custom and the device parameters are modified to create
a new custom device definition. In this example, Portrait is disabled so that the device definition is landscape-only:
Visual Studio
Visual Studio for Mac
Clicking Clone Device creates the new device definition, which now appears in the Device Definitions list:
Visual Studio
Visual Studio for Mac
Note that each user-created device definition is displayed with a green icon as shown above. When you return to
the Device selector menu, the new custom device definition is presented in the topmost section of the list (if you
do not see your custom device configuration in this list, try restarting the IDE ):
Visual Studio
Visual Studio for Mac
Selecting this device configuration modifies the layout to conform to the customizations created earlier (in this
case, landscape-only mode):
Visual Studio
Visual Studio for Mac
When you click Add language/region..., the Select Language dialog opens to display drop-down lists of
available languages and regions:
Visual Studio
Visual Studio for Mac
In this example, we have chosen fr (French) for the language and BE (Belgium) for the regional dialect of French.
Note that the Region field is optional because many languages can be specified without regard for specific
regions. When the Language pull-down menu is opened again, it displays the newly-added language/region
resource:
Visual Studio
Visual Studio for Mac
Note that if you add a new language but you do not create new resources for it, the added language will no longer
be shown the next time you open the project.
UI Mode
When you click the UI Mode pull-down menu, a list of modes is displayed, such as Normal, Car Dock, Desk
Dock, Television, Appliance, and Watch:
Visual Studio
Visual Studio for Mac
Below this list are the night modes Not Night and Night, followed by the layout directions Left to Right and
Right to Left (for information about Left to Right and Right to Left options, see LayoutDirection. The last items
in the Resource Qualifier Options dialog are the Round screens (for use with Android Wear) or Not Round
screens (for information about round and non-round screens, see Layouts). For more information about Android
UI modes, see UiModeManager.
This icon opens a dialog popover that provides a way to select from one of three Action Bar modes:
Standard – Consists of either a logo or icon and title text with an optional subtitle.
List – List navigation mode. Instead of static title text, this mode presents a list menu for navigation within
the activity (that is, it can be presented to the user as a dropdown list).
Tabs – Tab navigation mode. Instead of static title text, this mode presents a series of tabs for navigation
within the activity.
Themes
The Theme drop-down menu displays all of the themes defined in the project. Selecting More Themes opens a
dialog with a list of all themes available from the installed Android SDK, as shown below:
Visual Studio
Visual Studio for Mac
When a theme is selected, the Design Surface is updated to show the effect of the new theme. Note that this
change is made permanent only if the OK button is clicked in the Theme dialog. Once a theme has been selected,
it will be included in the Theme drop-down menu as shown below:
Visual Studio
Visual Studio for Mac
Android Version
The Android Version selector sets the Android version that is used to render the layout in the Designer. The
selector displays all versions that are compatible with the target framework version of the project:
Visual Studio
Visual Studio for Mac
The target framework version can be set in the project's settings under Properties > Application > Compile
using Android version. For more information about target framework version, see Understanding Android API
Levels.
The set of widgets available in the toolbox is determined by the target framework version of the project. This is
also true for the properties available in the Properties Window. The available list of widgets is not determined by
the value selected in the Version selector of the toolbar. For example, if you set the target version of the project to
Android 4.4, you can still select Android 6.0 in the toolbar version selector to see what the project looks like in
Android 6.0, but you won't be able to add widgets that are specific to Android 6.0 – you will still be limited to the
widgets that are available in Android 4.4.
Alternative Layout Views
4/12/2018 • 6 minutes to read • Edit Online
This topic explains how layouts can be versioned by using resource qualifiers. For example, there can be a version
of a layout that is only used when the device is in landscape mode and a layout version that is only for portrait
mode.
When you click the green plus sign next to New Version, the Create Layout Variation dialog opens so that you
can select the resource qualifiers for this layout variation:
Visual Studio
Visual Studio for Mac
In the following example, the resource qualifier for Screen Orientation is set to Landscape, and the Screen Size
is changed to Large. This creates a new layout version named large-land:
Visual Studio
Visual Studio for Mac
Note that the preview pane on the left displays the effects of the resource qualifier selections. Clicking Add creates
the alternative layout and switches the Designer to that layout. The Alternative Layout View preview pane
indicates which layout is loaded into the Designer via a small right pointer as indicated in the following screenshot:
Visual Studio
Visual Studio for Mac
Editing Alternative Layouts
When you create alternative layouts, it is often desirable to make a single change that applies to all forked versions
of a layout. For example, you may want to change the button text to yellow in all layouts. If you have a large
number of layouts, maintenance can quickly become cumbersome and error-prone if you need to propagate a
single change to all versions.
To simplify the maintenance of multiple layout versions, the Designer provides a Multi-edit mode that propagates
your changes across one or more layouts. When more than one layout is present, the Multi-edit icon is displayed:
Visual Studio
Visual Studio for Mac
When you click the Multi-edit icon, lines appear that indicate that the layouts are linked (as shown below ); that is,
when you make a change to one layout, that change is propagated to any linked layouts. You can unlink all layouts
by clicking the circled icon indicated in the following screenshot:
Visual Studio
Visual Studio for Mac
If you have more than two layouts, you can selectively toggle the edit button to the left of each layout preview to
determine which layouts are linked together. For example, if you want to make a single change that propagates to
the first and last of three layouts, you would first unlink the middle layout as shown here:
Visual Studio
Visual Studio for Mac
In this example, a change made to either the Default or long layout will be propagated to other layout but not to
the large-land layout.
Multi-Edit Example
In general, when you make a change to one layout, that same change is propagated to all other linked layouts. For
example, adding a new TextView widget to the Default layout and changing its text string to Portrait will cause
the same change to be made to all linked layouts. Here is how it looks in the Default layout:
Visual Studio
Visual Studio for Mac
The TextView is also added to the large-land layout view because it is linked to the Default layout:
Visual Studio
Visual Studio for Mac
But what if you want to make a change that is local to only one layout (that is, you don't want the change to be
propagated to any of the other layouts)? To do this, you must unlink the layout that you want to change before you
modify it, as explained next.
Making Local Changes
Suppose we want both layouts to have the added TextView , but we also want to change the text string in the
large-land layout to Landscape rather than Portrait . If we make this change to large-land while both layouts
are linked, the change will propagate back to the Default layout. Therefore, we must first unlink the two layouts
before we make the change. When we modify the text in large-land to Landscape , the Designer marks this
change with a red frame to indicate that the change is local to the large-land layout and is not propagated back to
the Default layout:
Visual Studio
Visual Studio for Mac
When you click the Default layout to view it, the TextView text string is still set to Portrait .
Handling Conflicts
If you decide to change the color of the text in the Default layout to green, you'll see a warning icon appear on the
linked layout. Clicking that layout opens the layout to reveal the conflict. The widget that caused the conflict is
highlighted with a red frame and the following message is displayed: Recent changes have caused conflicts in this
alternative layout.
Visual Studio
Visual Studio for Mac
A conflict box is displayed on the right of the widget to explain the conflict:
The conflict box shows the list of properties that have changed and it lists their values. Clicking Ignore Conflict
applies the property change only to this widget. Clicking Apply applies the property change to this widget as well
as to the counterpart widget in the linked Default layout. If all property changes are applied, the conflict is
automatically discarded.
View Group Conflicts
Property changes are not the only source of conflicts. Conflicts can be detected when inserting or removing
widgets. For example, when the large-land layout is unlinked from the Default layout, and the TextView in the
large-land layout is dragged and dropped above the Button , the Designer marks the moved widget to indicate
the conflict:
Visual Studio
Visual Studio for Mac
However, there is no marker on the Button . Although the position of the Button has changed, the Button shows
no applied changes that are specific to the large-land configuration.
If a CheckBox is added to the Default layout, another conflict is generated, and a warning icon is displayed over
the large-land layout:
Visual Studio
Visual Studio for Mac
Clicking the large-land layout reveals the conflict. The following message is displayed: Recent changes have
caused conflicts in this alternative layout.
Visual Studio
Visual Studio for Mac
As seen in the previous example with the Button , the CheckBox does not have a red change marker because only
the LinearLayout has changes that were applied in the large-land layout.
Conflict Persistence
Conflicts are persisted in the layout file as XML comments, as shown here:
<!-- Widget Inserted Conflict | id:__root__ | @+id/checkBox1 -->
Therefore, when a project is closed and reopened, all the conflicts will still be there – even the ones that have been
ignored.
Material Design Features
4/12/2018 • 9 minutes to read • Edit Online
This topic describes Designer features that make it easier for developers to create Material Design-compliant
layouts. This section introduces and explains how to use the Material Grid, the Material Color Palette, the
Typographic Scale, and the Theme Editor.
Evolve 2016: Everyone Can Create Beautiful Apps with Material Design
Overview
The Xamarin.Android Designer includes features that make it easier for you to create Material-Design-compliant
layouts. If you are not familiar with Material Design, see the Material Design Introduction.
In this guide, we'll have a look at the following Designer features:
Material Grid – An overlay on the Design Surface that shows a grid, spacing, and keylines to help you place
layout widgets according to Material Design guidelines.
Material Color Palette – A Property Pad dialog that assists you in choosing a color from the official Material
Design palette.
Typographic Scale – A Property Pad dialog that provides you with a choice of Material Design-compliant
settings for the textAppearance property of text fields.
Theme Editor – A small color resource editor that lets you set color information for a subset of a theme. For
example, you can preview and modify Material colors such as colorPrimary , colorPrimaryDark , and
colorAccent .
We'll have look at each of these features and provide examples of how to use them.
Visual Studio
Visual Studio for Mac
Each of these overlay items is configurable. When you click the ellipsis next to the Material Design Grid menu, a
dialog popover opens that allows you to disable/enable the grid, configure the placement of keylines, and set the
spacings. Note that all values are expressed in dp (density-independent pixels):
To add a new keyline, enter a new offset value in the Offset box, select a location (left, top, right, or bottom ) and
click the + icon to add the new keyline.
Similarly, to add a new spacing, enter the size and offset (in dp) into the Size and Offset boxes, respectively. Select
a location (left, top, right, or bottom ) and click the + icon to add the new spacing.
When you change these configuration values, they are saved in the layout XML file and reused when you open the
layout again.
Theme Editor
The Theme Editor lets you customize color information for a subset of theme attributes. To open the Theme
Editor, click the paintbrush icon on the toolbar:
Visual Studio
Visual Studio for Mac
Although the Theme Editor is accessible from the toolbar for all target Android versions and API levels, only a
subset of the capabilities described below are available if the target API level is earlier than API 21 (Android 5.0
Lollipop).
The left-hand panel of the Theme Editor displays the list of colors that make up the currently selected theme (in
this example, we are using the Default Theme ):
Visual Studio
Visual Studio for Mac
When you select a color on the left, the right-hand panel provides the following tabs to help you edit that color:
Inherit – Displays a style inheritance diagram for the selected color and lists the resolved color and color
code assigned to that theme color.
Color Picker – Lets you change the selected to color to any arbitrary value.
Material Palette – Lets you change the selected to color to a value that conforms to Material Design.
Resources – Lets you change the selected to color to one of the other existing color resources in the theme.
Let's look at each one of these tabs in detail.
Inherit Tab
As seen in the following example, the Inherit tab lists the style inheritance for the Background color of the
Default Theme:
Visual Studio
Visual Studio for Mac
In this example, the Default Theme inherits from a style that uses @color/background_material_dark but overrides
it with color/material_grey_850 , which has a color code value of #ff303030 . For more information about style
inheritance, see Styles and Themes.
Color Picker
The following screenshot illustrates the Color Picker:
Visual Studio
Visual Studio for Mac
In this example, the Background color can be changed to any value through various means:
Clicking a color directly.
Entering hue, saturation, and brightness values.
Entering RGB (red, green, blue) values in decimal.
Setting the alpha (opacity) for the selected color.
Entering the hexadecimal color code directly.
The color you choose in the Color Picker is not restricted to Material Design guidelines or to the set of available
color resources.
Resources
The Resources tab offers a list of color resources that are already present in the theme:
Visual Studio
Visual Studio for Mac
Using the Resources tab constrains your choices to this list of colors. Keep in mind that if you choose a color
resource that is already assigned to another part of the theme, two adjacent elements of the UI may "run together"
(because they have the same color) and become difficult for the user to distinguish.
Material Palette
Visual Studio
Visual Studio for Mac
The Material Palette tab opens the Material Design Color Palette. Choosing a color value from this palette
constrains your color choice so that it is consistent with Material Design guidelines.
The top of the color palette displays primary Material Design colors while the bottom of the palette displays a
range of hues for the selected primary color. For example, when you select Indigo, a collection of Indigo hues is
displayed at the bottom of the dialog. When you select a hue, the color of the property is changed to the selected
hue. In the following example, the Background Tint of the button is changed to Indigo 500:
Background Tint is set to the color code for Indigo 500 ( #ff3f51b5 ), and the Designer updates the background
color to reflect this change:
For more information about the Material Design color palette, see the Material Design Color Palette Guide.
Creating a New Theme
In the following example, we'll use the Material Palette to create a new custom theme. First, we'll change the
Background color to Blue 900:
Visual Studio
Visual Studio for Mac
When a color resource is changed, a message pops up with the message, The current theme has unsaved changes:
Visual Studio
Visual Studio for Mac
The Background color in the Designer has changed to the new color selection, but this change has not yet been
saved. Two choices are offered for how to handle the change:
Discard Changes – Discards the new color choice (or choices) and reverts the theme to its original state.
Create New Theme – Creates a new theme that is derived from the currently-selected theme and uses the
color overrides made in the Theme Editor.
When you click Create New Theme, one of the following will happen, depending on the selected theme:
If the currently selected theme on the Designer is not a project theme, you are presented with the option to
create a new resource file with the customized theme (using the selected theme as the parent of the
customized theme). The Designer switches to the customized theme after it is created.
If the currently selected theme is a project theme that is defined in one location, you are presented with the
Update theme option; clicking this option updates the currently selected theme rather than creating a new
one.
If the currently selected theme is a project theme that is defined in multiple locations (for example, in
differently-suffixed values folders such as values-v21), you are presented a dialog that asks for a new
location for saving the customized theme.
Continuing the previous example, clicking Create New Theme results in the creation of a new theme called
Custom:
Visual Studio
Visual Studio for Mac
Because the currently-selected theme is not a project theme, there is no dialog to update the selected theme or to
specify a new location.
Summary
This topic described the Material Design features available in the Xamarin.Android Designer. It explained how to
enable and configure the Material Design Grid, how to use the Material Design Color Palette to edit color
properties, and how to use the Typographic Scale selector to configure text properties. It also demonstrated how
to use the Theme Editor to create new custom themes that conform to Material Design guidelines. For more
information about Xamarin.Android support for Material Design, see Material Theme.
Related Links
Material Theme
Material Design Introduction
Material Theme
4/12/2018 • 9 minutes to read • Edit Online
Material Theme is a user interface style that determines the look and feel of views and activities starting with
Android 5.0 (Lollipop). Material Theme is built into Android 5.0, so it is used by the system UI as well as by
applications. Material Theme is not a "theme" in the sense of a system-wide appearance option that a user can
dynamically choose from a settings menu. Rather, Material Theme can be thought of as a set of related built-in
base styles that you can use to customize the look and feel of your app.
Android provides three Material Theme flavors:
Theme.Material – Dark version of Material Theme; this is the default flavor in Android 5.0.
Theme.Material.Light – Light version of Material Theme.
Theme.Material.Light.DarkActionBar – Light version of Material Theme, but with a dark action bar.
You can derive from Material Theme to create your own theme, overriding some or all color attributes. For
example, you can create a theme that derives from Theme.Material.Light , but overrides the app bar color to
match the color of your brand. You can also style individual views; for example, you can create a style for
CardView that has more rounded corners and uses a darker background color.
You can use a single theme for an entire app, or you can use different themes for different screens (activities) in an
app. In the above screenshots, for example, a single app uses a different theme for each activity to demonstrate
the built-in color schemes. Radio buttons switch the app to different activities, and, as a result, display different
themes.
Because Material Theme is supported only on Android 5.0 and later, you cannot use it (or a custom theme derived
from Material Theme) to theme your app for running on earlier versions of Android. However, you can configure
your app to use Material Theme on Android 5.0 devices and gracefully fall back to an earlier theme when it runs
on older versions of Android (see the Compatibility section of this article for details).
Requirements
The following is required to use the new Android 5.0 Material Theme features in Xamarin-based apps:
Xamarin.Android – Xamarin.Android 4.20 or later must be installed and configured with either Visual
Studio or Visual Studio for Mac.
Android SDK – Android 5.0 (API 21) or later must be installed via the Android SDK Manager.
Java JDK 1.8 – JDK 1.7 can be used if you are specifically targetting API level 23 and earlier. JDK 1.8 is
available from Oracle.
To learn how to configure an Android 5.0 app project, see Setting Up an Android 5.0 Project.
The following example configures the application MyApp to use the light theme:
<application android:label="MyApp"
android:theme="@android:style/Theme.Material.Light">
</application>
Alternately, you can set the application Theme attribute in AssemblyInfo.cs (or Properties.cs). For example:
[assembly: Application(Theme="@android:style/Theme.Material.Light")]
When the application theme is set to @android:style/Theme.Material.Light , every activity in MyApp will be
displayed using Theme.Material.Light .
Theming an Activity
To theme an activity, you add a Theme setting to the [Activity] attribute above your activity declaration and
assign Theme to the Material Theme flavor that you want to use. The following example themes an activity with
Theme.Material.Light :
[Activity(Theme = "@android:style/Theme.Material.Light",
Label = "MyApp", MainLauncher = true, Icon = "@drawable/icon")]
Other activities in this app will use the default Theme.Material dark color scheme (or, if configured, the application
theme setting).
By default, statusBarColor is set to the value of colorPrimaryDark . You can set statusBarColor to a solid color, or
you can set it to @android:color/transparent to make the status bar transparent. The navigation bar can also be
made transparent by setting navigationBarColor to @android:color/transparent .
Creating a Custom App Theme
You can create a custom app theme by creating and modifying files in the Resources folder of your app project.
To style your app with a custom theme, use the following steps:
Create a colors.xml file in Resources/values — you use this file to define your custom theme colors. For
example, you can paste the following code into colors.xml to help you get started:
<?xml version="1.0" encoding="UTF-8" ?>
<resources>
<color name="my_blue">#3498DB</color>
<color name="my_green">#77D065</color>
<color name="my_purple">#B455B6</color>
<color name="my_gray">#738182</color>
</resources>
Modify this example file to define the names and color codes for color resources that you will use in your
custom theme.
Create a Resources/values-v21 folder. In this folder, create a styles.xml file:
Note that Resources/values-v21 is specific to Android 5.0 – older versions of Android will not read files in
this folder.
Add a resources node to styles.xml and define a style node with the name of your custom theme. For
example, here is a styles.xml file that defines MyCustomTheme (derived from the built-in
Theme.Material.Light theme style):
At this point, an app that uses MyCustomTheme will display the stock Theme.Material.Light theme without
customizations:
Add color customizations to styles.xml by defining the colors of layout attributes that you want to change.
For example, to change the app bar color to my_blue and change the color of UI controls to my_purple ,
add color overrides to styles.xml that refer to color resources configured in colors.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<resources>
<!-- Inherit from the light Material Theme -->
<style name="MyCustomTheme" parent="android:Theme.Material.Light">
<!-- Override the app bar color -->
<item name="android:colorPrimary">@color/my_blue</item>
<!-- Override the color of UI controls -->
<item name="android:colorAccent">@color/my_purple</item>
</style>
</resources>
With these changes in place, an app that uses MyCustomTheme will display an app bar color in my_blue and UI
controls in my_purple , but use the Theme.Material.Light color scheme everywhere else:
In this example, MyCustomTheme borrows colors from Theme.Material.Light for the background color, status bar,
and text colors, but it changes the color of the app bar to my_blue and sets the color of the radio button to
my_purple .
In your layout, set the style attribute for that view to match the custom style name that you chose in the
previous step. For example:
<android.support.v7.widget.CardView
style="@style/CardView.MyBlue"
android:layout_width="200dp"
android:layout_height="100dp"
android:layout_gravity="center_horizontal">
The following screenshot provides an example of the default CardView (shown on the left) as compared to a
CardView that has been styled with the custom CardView.MyBlue theme (shown on the right):
In this example, the custom CardView is displayed with the background color my_blue and an 18dp corner radius.
Compatibility
To style your app so that it uses Material Theme on Android 5.0 but automatically reverts to a downward-
compatible style on older Android versions, use the following steps:
Define a custom theme in Resources/values-v21/styles.xml that derives from a Material Theme style. For
example:
<resources>
<style name="MyCustomTheme" parent="android:Theme.Material.Light">
<!-- Your customizations go here -->
</style>
</resources>
Define a custom theme in Resources/values/styles.xml that derives from an older theme, but uses the same
theme name as above. For example:
<resources>
<style name="MyCustomTheme" parent="android:Theme.Holo.Light">
<!-- Your customizations go here -->
</style>
</resources>
In AndroidManifest.xml, configure your app with the custom theme name. For example:
<application android:label="MyApp"
android:theme="@style/MyCustomTheme">
</application>
Alternately, you can style a specific activity using your custom theme:
If your theme uses colors defined in a colors.xml file, be sure to place this file in Resources/values (rather than
Resources/values-v21) so that both versions of your custom theme can access your color definitions.
When your app runs on an Android 5.0 device, it will use the theme definition specified in Resources/values-
v21/styles.xml. When this app runs on older Android devices, it will automatically fall back to the theme
definition specified in Resources/values/styles.xml.
For more information about theme compatibility with older Android versions, see Alternate Resources.
Summary
This article introduced the new Material Theme user interface style included in Android 5.0 (Lollipop). It described
the three built-in Material Theme flavors that you can use to style your app, it explained how to create a custom
theme for branding your app, and it provided an example of how to theme an individual view. Finally, this article
explained how to use Material Theme in your app while maintaining downward compatibility with older versions
of Android.
Related Links
ThemeSwitcher (sample)
Introduction to Lollipop
CardView
Alternate Resources
Android L Developer Preview
Material Design
Material Design Principles
Maintaining Compatibility
User Profile
4/12/2018 • 2 minutes to read • Edit Online
Android has supported enumerating contacts with the ContactsContract provider since API Level 5. For example,
listing contacts is as simple as using the ContactContracts.Contacts class as shown in the following code example:
// Setup the "projection" (columns we want) for only the ID and display name:
string[] projection = {
ContactsContract.Contacts.InterfaceConsts.Id,
ContactsContract.Contacts.InterfaceConsts.DisplayName };
Beginning with Android 4 (API Level 14), the ContactsContact.Profile class is available through the
ContactsContract provider. The ContactsContact.Profile provides access to the personal profile for the owner of a
device, which includes contact data such as the device owner's name and phone number.
Required Permissions
To read and write contact data, applications must request the READ_CONTACTS and WRITE_CONTACTS permissions,
respectively. Additionally, to read and edit the user profile, applications must request the READ_PROFILE and
WRITE_PROFILE permissions.
// Setup the "projection" (column we want) for only the display name:
string[] projection = {
ContactsContract.Contacts.InterfaceConsts.DisplayName };
When running the above code, the user profile is displayed as illustrated in the following screenshot:
Working with the user profile is similar to interacting with other data in Android, and it offers an additional level of
device personalization.
Related Links
ContactsProviderDemo (sample)
Introducing Ice Cream Sandwich
Android 4.0 Platform
Splash Screen
5/14/2018 • 6 minutes to read • Edit Online
An Android app takes some time to to start up, especially when the app is first launched on a device. A splash
screen may display start up progress to the user or to indicate branding.
Overview
An Android app takes some time to to start up, especially during the first time the app is run on a device
(sometimes this is referred to as a cold start). The splash screen may display start up progress to the user, or it may
display branding information to identify and promote the application.
This guide discusses one technique to implement a splash screen in an Android application. It covers the following
steps:
1. Creating a drawable resource for the splash screen.
2. Defining a new theme that will display the drawable resource.
3. Adding a new Activity to the application that will be used as the splash screen defined by the theme created
in the previous step.
Requirements
This guide assumes that the application targets Android API level 15 (Android 4.0.3) or higher. The application
must also have the Xamarin.Android.Support.v4 and Xamarin.Android.Support.v7.AppCompat NuGet
packages added to the project.
All of the code and XML in this guide may be found in the SplashScreen sample project for this guide.
This will center the splash screen image splash.png on a background specified by the
layer-list
@color/splash_backgroundresource. Place this file in the Resources/drawable folder (for example,
Resources/drawable/splash_screen.xml).
After the splash screen drawable has been created, the next step is to create a theme for the splash screen.
Implementing a Theme
To create a custom theme for the splash screen Activity, edit (or add) the file values/styles.xml and create a new
style element for the splash screen. A sample values/style.xml file is shown below with a style named
MyTheme.Splash:
<resources>
<style name="MyTheme.Base" parent="Theme.AppCompat.Light">
</style>
MyTheme.Splash is very spartan – it declares the window background, explicitly removes the title bar from the
window, and declares that it is full-screen. If you want to create a splash screen that emulates the UI of your app
before the activity inflates the first layout, you can use windowContentOverlay rather than windowBackground in your
style definition. In this case, you must also modify the splash_screen.xml drawable so that it displays an
emulation of your UI.
Create a Splash Activity
Now we need a new Activity for Android to launch that has our splash image and performs any startup tasks. The
following code is an example of a complete splash screen implementation:
SplashActivity explicitly uses the theme that was created in the previous section, overriding the default theme of
the application. There is no need to load a layout in OnCreate as the theme declares a drawable as the background.
It is important to set the NoHistory=true attribute so that the Activity is removed from the back stack. To prevent
the back button from canceling the startup process, you can also override OnBackPressed and have it do nothing:
[Activity(Label = "@string/ApplicationName")]
public class MainActivity : AppCompatActivity
{
// Code omitted for brevity
}
Landscape Mode
The splash screen implemented in the previous steps will display correctly in both portrait and landscape mode.
However, in some cases it is necessary to have separate splash screens for portrait and landscape modes (for
example, if the splash image is full-screen).
To add a splash screen for landscape mode, use the following steps:
1. In the Resources/drawable folder, add the landscape version of the splash screen image you want to use.
In this example, splash_logo_land.png is the landscape version of the logo that was used in the above
examples (it uses white lettering instead of blue).
2. In the Resources/drawable folder, create a landscape version of the layer-list drawable that was defined
earlier (for example, splash_screen_land.xml). In this file, set the bitmap path to the landscape version of
the splash screen image. In the following example, splash_screen_land.xml uses splash_logo_land.png:
6. Modify values-land/colors.xml to configure the colors you want to use for the landscape version of the
splash screen. In this example, the splash background color is changed to blue for landscape mode:
7. Build and run the app again. Rotate the device to landscape mode while the splash screen is still displayed.
The splash screen changes to the landscape version:
Note that the use of a landscape-mode splash screen does not always provide a seamless experience. By default,
Android launches the app in portrait mode and transitions it to landscape mode even if the device is already in
landscape mode. As a result, if the app is launched while the device is in landscape mode, the device briefly
presents the portrait splash screen and then animates rotation from the portrait to the landscape splash screen.
Unfortunately, this initial portrait-to-landscape transition takes place even when
ScreenOrientation = Android.Content.PM.ScreenOrientation.Landscape is specified in the splash Activity's flags. The
best way to work around this limitation is to create a single splash screen image that renders correctly in both
portrait and landscape modes.
Summary
This guide discussed one way to implement a splash screen in a Xamarin.Android application; namely, applying a
custom theme to the launch activity.
Related Links
SplashScreen (sample)
layer-list Drawable
Material Design Patterns - Launch Screens
Layouts
4/12/2018 • 2 minutes to read • Edit Online
Layouts are used to arrange the elements that make up the UI interface of a screen (such as an Activity). The
following sections explain how to use the most commonly-used layouts in Xamarin.Android apps.
LinearLayout is a view group that displays child view elements in a linear direction, either vertically or
horizontally.
RelativeLayout is view group that displays child view elements in a relative position. The position of a view
can be specified as relative to sibling elements.
TableLayout is a view group that displays child view elements in rows and columns.
RecyclerView is a UI element that displays a collection of items in a list or a grid, enabling the user to scroll
through the collection.
ListView is a view group that creates a list of scrollable items. The list items are automatically inserted into
the list using a list adapter. The ListView is an important UI component of Android applications because it
is used everywhere from short lists of menu options to long lists of contacts or internet favorites. It provides
a simple way to present a scrolling list of rows that can either be formatted with a built-in style or
customized extensively. A ListView instance requires an Adapter to feed it with data contained in row views.
GridView is a UI element that displays items in a two-dimensional grid that can be scrolled.
GridLayout is a view group that supports laying out views in a 2D grid, similar to an HTML table.
Tabbed Layouts are a popular user interface pattern in mobile applications because of their simplicity and
usability. They provide a consistent, easy way to navigate between various screens in an application.
LinearLayout
6/7/2018 • 2 minutes to read • Edit Online
LinearLayout is a ViewGroup that displays child View elements in a linear direction, either vertically or
horizontally.
You should be careful about over-using the LinearLayout . If you begin nesting multiple LinearLayout s, you may
want to consider using a RelativeLayout instead.
Start a new project named HelloLinearLayout.
Open Resources/Layout/Main.axml and insert the following:
<LinearLayout
android:orientation= "horizontal"
android:layout_width= "match_parent"
android:layout_height= "match_parent"
android:layout_weight= "1" >
<TextView
android:text= "red"
android:gravity= "center_horizontal"
android:background= "#aa0000"
android:layout_width= "wrap_content"
android:layout_height= "match_parent"
android:layout_weight= "1" />
<TextView
android:text= "green"
android:gravity= "center_horizontal"
android:background= "#00aa00"
android:layout_width= "wrap_content"
android:layout_height= "match_parent"
android:layout_weight= "1" />
<TextView
android:text= "blue"
android:gravity= "center_horizontal"
android:background= "#0000aa"
android:layout_width= "wrap_content"
android:layout_height= "match_parent"
android:layout_weight= "1" />
<TextView
android:text= "yellow"
android:gravity= "center_horizontal"
android:background= "#aaaa00"
android:layout_width= "wrap_content"
android:layout_height= "match_parent"
android:layout_weight= "1" />
</LinearLayout>
<LinearLayout
android:orientation= "vertical"
android:layout_width= "match_parent"
android:layout_height= "match_parent"
android:layout_weight= "1" >
<TextView
android:text= "row one"
android:textSize= "15pt"
android:textSize= "15pt"
android:layout_width= "match_parent"
android:layout_height= "wrap_content"
android:layout_weight= "1" />
<TextView
android:text= "row two"
android:textSize= "15pt"
android:layout_width= "match_parent"
android:layout_height= "wrap_content"
android:layout_weight= "1" />
<TextView
android:text= "row three"
android:textSize= "15pt"
android:layout_width= "match_parent"
android:layout_height= "wrap_content"
android:layout_weight= "1" />
<TextView
android:text= "row four"
android:textSize= "15pt"
android:layout_width= "match_parent"
android:layout_height= "wrap_content"
android:layout_weight= "1" />
</LinearLayout>
</LinearLayout>
Carefully inspect this XML. There is a root LinearLayout that defines its orientation to be vertical – all child View s
(of which it has two) will be stacked vertically. The first child is another LinearLayout that uses a horizontal
orientation and the second child is a LinearLayout that uses a vertical orientation. Each of these nested
LinearLayout s contain several TextView elements, which are oriented with each other in the manner defined by
their parent LinearLayout .
Now open HelloLinearLayout.cs and be sure it loads the Resources/Layout/Main.axml layout in the
OnCreate() method:
The SetContentView(int) method loads the layout file for the Activity , specified by the resource ID –
Resources.Layout.Main refers to the Resources/Layout/Main.axml layout file.
Run the application. You should see the following:
Notice how the XML attributes define each View's behavior. Try experimenting with different values for
to see how the screen real estate is distributed based on the weight of each element. See
android:layout_weight
the Common Layout Objects document for more about how LinearLayout handles the android:layout_weight
attribute.
References
LinearLayout
TextView
Portions of this page are modifications based on work created and shared by the Android Open Source Project
and used according to terms described in the Creative Commons 2.5 Attribution License.
RelativeLayout
7/3/2018 • 2 minutes to read • Edit Online
RelativeLayout is a ViewGroup that displays child View elements in relative positions. The position of a View can
be specified as relative to sibling elements (such as to the left-of or below a given element) or in positions relative
to the RelativeLayout area (such as aligned to the bottom, left of center).
A RelativeLayout is a very powerful utility for designing a user interface because it can eliminate nested
ViewGroup s. If you find yourself using several nested LinearLayout groups, you may be able to replace them with
a single RelativeLayout .
Start a new project named HelloRelativeLayout.
Open the Resources/Layout/Main.axml file and insert the following:
The SetContentView(int) method loads the layout file for the Activity , specified by the resource ID —
Resource.Layout.Main refers to the Resources/Layout/Main.axml layout file.
Run the application. You should see the following layout:
Resources
RelativeLayout
RelativeLayout.LayoutParams
TextView
EditText
Button
Portions of this page are modifications based on work created and shared by the Android Open Source Project
and used according to terms described in the Creative Commons 2.5 Attribution License.
TableLayout
4/12/2018 • 2 minutes to read • Edit Online
TableLayout is a ViewGroup that displays child View elements in rows and columns.
Start a new project named HelloTableLayout.
Open the Resources/Layout/Main.axml file and insert the following:
<TableRow>
<TextView
android:layout_column="1"
android:text="Open..."
android:padding="3dip"/>
<TextView
android:text="Ctrl-O"
android:gravity="right"
android:padding="3dip"/>
</TableRow>
<TableRow>
<TextView
android:layout_column="1"
android:text="Save..."
android:padding="3dip"/>
<TextView
android:text="Ctrl-S"
android:gravity="right"
android:padding="3dip"/>
</TableRow>
<TableRow>
<TextView
android:layout_column="1"
android:text="Save As..."
android:padding="3dip"/>
<TextView
android:text="Ctrl-Shift-S"
android:gravity="right"
android:padding="3dip"/>
</TableRow>
<View
android:layout_height="2dip"
android:background="#FF909090"/>
<TableRow>
<TextView
android:text="X"
android:padding="3dip"/>
<TextView
android:text="Import..."
android:padding="3dip"/>
</TableRow>
<TableRow>
<TextView
android:text="X"
android:padding="3dip"/>
<TextView
android:text="Export..."
android:padding="3dip"/>
<TextView
android:text="Ctrl-E"
android:gravity="right"
android:padding="3dip"/>
</TableRow>
<View
android:layout_height="2dip"
android:background="#FF909090"/>
<TableRow>
<TextView
android:layout_column="1"
android:text="Quit"
android:padding="3dip"/>
</TableRow>
</TableLayout>
Notice how this resembles the structure of an HTML table. The TableLayout element is like the HTML <table>
element; TableRow is like a <tr> element; but for the cells, you can use any kind of View element. In this example,
a TextView is used for each cell. In between some of the rows, there is also a basic View , which is used to draw a
horizontal line.
Make sure your HelloTableLayout Activity loads this layout in the OnCreate() method:
The SetContentView(int) method loads the layout file for the Activity , specified by the resource ID —
Resource.Layout.Main refers to the Resources/Layout/Main.axml layout file.
Run the application. You should see the following:
References
TableLayout
TableRow
TextView
Portions of this page are modifications based on work created and shared by the Android Open Source Project
and used according to terms described in the Creative Commons 2.5 Attribution License.
RecyclerView
4/12/2018 • 3 minutes to read • Edit Online
RecyclerView is a view group for displaying collections; it is designed to be a more flexible replacement for older
view groups such as ListView and GridView. This guide explains how to use and customize RecyclerView in
Xamarin.Android applications.
RecyclerView
Many apps need to display collections of the same type (such as messages, contacts, images, or songs); often, this
collection is too large to fit on the screen, so the collection is presented in a small window that can smoothly scroll
through all items in the collection. RecyclerView is an Android widget that displays a collection of items in a list or
a grid, enabling the user to scroll through the collection. The following is a screenshot of an example app that uses
RecyclerView to display email inbox contents in a vertical scrolling list:
RecyclerViewdoes not offer an item-click event when a user taps an item; instead, item-click events are
handled by helper classes. By contrast, ListView offers an item-click event.
RecyclerView enhances performance by recycling views and by enforcing the view -holder pattern, which
eliminates unnecessary layout resource lookups. Use of the view -holder pattern is optional in ListView .
RecyclerView is based on a modular design that makes it easier to customize. For example, you can plug in
a different layout policy without significant code changes to your app. By contrast, ListView is relatively
monolithic in structure.
RecyclerView includes built-in animations for item add and remove. ListView animations require some
additional effort on the part of the app developer.
Sections
RecyclerView Parts and Functionality
This topic explains how the Adapter , LayoutManager , and ViewHolder work together as helper classes to support
RecyclerView . It provides a high-level overview of each of these helper classes and explains how you use them in
your app.
A Basic RecyclerView Example
This topic builds on the information provided in RecyclerView Parts and Functionality by providing real code
examples of how the various RecyclerView elements are implemented to build a real-world photo-browsing app.
Extending the RecyclerView Example
This topic adds additional code to the example app presented in A Basic RecyclerView Example to demonstrate
how to handle item-click events and update RecyclerView when the underlying data source changes.
Summary
This guide introduced the Android RecyclerView widget; it explained how to add the RecyclerView support
library to Xamarin.Android projects, how RecyclerView recycles views, how it enforces the view -holder pattern for
efficiency, and how the various helper classes that make up RecyclerView collaborate to display collections. It
provided example code to demonstrate how RecyclerView is integrated into an application, it explained how to
tailor RecyclerView 's layout policy by plugging in different layout managers, and it described how to handle item
click events and notify RecyclerView of data source changes.
For more information about RecyclerView , see the RecyclerView class reference.
Related Links
RecyclerViewer (sample)
Introduction to Lollipop
RecyclerView
RecyclerView Parts and Functionality
7/13/2018 • 8 minutes to read • Edit Online
RecyclerView handles some tasks internally (such as the scrolling and recycling of views), but it is essentially a
manager that coordinates helper classes to display a collection. RecyclerView delegates tasks to the following
helper classes:
Adapter – Inflates item layouts (instantiates the contents of a layout file) and binds data to views that are
displayed within a RecyclerView . The adapter also reports item-click events.
LayoutManager – Measures and positions item views within a RecyclerView and manages the policy for
view recycling.
ViewHolder – Looks up and stores view references. The view holder also helps with detecting item-view
clicks.
ItemDecoration – Allows an app to add special drawing and layout offsets to specific views for drawing
dividers between items, highlights, and visual grouping boundaries.
ItemAnimator – Defines the animations that take place during item actions or as changes are made to the
adapter.
The relationship between the RecyclerView , LayoutManager , and Adapter classes is depicted in the following
diagram:
As this figure illustrates, the LayoutManager can be thought of as the intermediary between the Adapter and the
RecyclerView . The LayoutManager makes calls into Adapter methods on behalf of the RecyclerView . For example,
the LayoutManager calls an Adapter method when it is time to create a new view for a particular item position in
the RecyclerView . The Adapter inflates the layout for that item and creates a ViewHolder instance (not shown) to
cache references to the views at that position. When the LayoutManager calls the Adapter to bind a particular item
to the data set, the Adapter locates the data for that item, retrieves it from the data set, and copies it to the
associated item view.
When using RecyclerView in your app, creating derived types of the following classes is required:
RecyclerView.Adapter – Provides a binding from your app's data set (which is specific to your app) to item
views that are displayed within the RecyclerView . The adapter knows how to associate each item-view
position in the RecyclerView to a specific location in the data source. In addition, the adapter handles the
layout of the contents within each individual item view and creates the view holder for each view. The
adapter also reports item-click events that are detected by the item view.
RecyclerView.ViewHolder – Caches references to the views in your item layout file so that resource lookups
are not repeated unnecessarily. The view holder also arranges for item-click events to be forwarded to the
adapter when a user taps the view -holder's associated item view.
RecyclerView.LayoutManager – Positions items within the RecyclerView . You can use one of several
predefined layout managers or you can implement your own custom layout manager. RecyclerView
delegates the layout policy to the layout manager, so you can plug in a different layout manager without
having to make significant changes to your app.
Also, you can optionally extend the following classes to change the look and feel of RecyclerView in your app:
RecyclerView.ItemDecoration
RecyclerView.ItemAnimator
If you do not extend ItemDecoration and ItemAnimator , RecyclerView uses default implementations. This guide
does not explain how to create custom ItemDecoration and ItemAnimator classes; for more information about
these classes, see RecyclerView.ItemDecoration and RecyclerView.ItemAnimator.
How View Recycling Works
RecyclerView does not allocate an item view for every item in your data source. Instead, it allocates only the
number of item views that fit on the screen and it reuses those item layouts as the user scrolls. When the view first
scrolls out of sight, it goes through the recycling process illustrated in the following figure:
1. When a view scrolls out of sight and is no longer displayed, it becomes a scrap view.
2. The scrap view is placed in a pool and becomes a recycle view. This pool is a cache of views that display the
same type of data.
3. When a new item is to be displayed, a view is taken from the recycle pool for reuse. Because this view must
be re-bound by the adapter before being displayed, it is called a dirty view.
4. The dirty view is recycled: the adapter locates the data for the next item to be displayed and copies this data
to the views for this item. References for these views are retrieved from the view holder associated with the
recycled view.
5. The recycled view is added to the list of items in the RecyclerView that are about to go on-screen.
6. The recycled view goes on-screen as the user scrolls the RecyclerView to the next item in the list.
Meanwhile, another view scrolls out of sight and is recycled according to the above steps.
In addition to item-view reuse, RecyclerView also uses another efficiency optimization: view holders. A view
holder is a simple class that caches view references. Each time the adapter inflates an item-layout file, it also
creates a corresponding view holder. The view holder uses FindViewById to get references to the views inside the
inflated item-layout file. These references are used to load new data into the views every time the layout is
recycled to show new data.
The Layout Manager
The layout manager is responsible for positioning items in the RecyclerView display; it determines the
presentation type (a list or a grid), the orientation (whether items are displayed vertically or horizontally), and
which direction items should be displayed (in normal order or in reverse order). The layout manager is also
responsible for calculating the size and position of each item in the RecycleView display.
The layout manager has an additional purpose: it determines the policy for when to recycle item views that are no
longer visible to the user. Because the layout manager is aware of which views are visible (and which are not), it is
in the best position to decide when a view can be recycled. To recycle a view, the layout manager typically makes
calls to the adapter to replace the contents of a recycled view with different data, as described previously in How
View Recycling Works.
You can extend RecyclerView.LayoutManager to create your own layout manager, or you can use a predefined
layout manager. RecyclerView provides the following predefined layout managers:
LinearLayoutManager – Arranges items in a column that can be scrolled vertically, or in a row that can be
scrolled horizontally.
GridLayoutManager – Displays items in a grid.
StaggeredGridLayoutManager – Displays items in a staggered grid, where some items have different heights
and widths.
To specify the layout manager, instantiate your chosen layout manager and pass it to the SetLayoutManager
method. Note that you must specify the layout manager – RecyclerView does not select a predefined layout
manager by default.
For more information about the layout manager, see the RecyclerView.LayoutManager class reference.
The View Holder
The view holder is a class that you define for caching view references. The adapter uses these view references to
bind each view to its content. Every item in the RecyclerView has an associated view holder instance that caches
the view references for that item. To create a view holder, use the following steps to define a class to hold the exact
set of views per item:
1. Subclass RecyclerView.ViewHolder .
2. Implement a constructor that looks up and stores the view references.
3. Implement properties that the adapter can use to access these references.
A detailed example of a ViewHolder implementation is presented in A Basic RecyclerView Example. For more
information about RecyclerView.ViewHolder , see the RecyclerView.ViewHolder class reference.
The Adapter
Most of the "heavy-lifting" of the RecyclerView integration code takes place in the adapter. RecyclerView requires
that you provide an adapter derived from RecyclerView.Adapter to access your data source and populate each
item with content from the data source. Because the data source is app-specific, you must implement adapter
functionality that understands how to access your data. The adapter extracts information from the data source and
loads it into each item in the RecyclerView collection.
The following drawing illustrates how the adapter maps content in a data source through view holders to
individual views within each row item in the RecyclerView :
The adapter loads each RecyclerView row with data for a particular row item. For row position P, for example, the
adapter locates the associated data at position P within the data source and copies this data to the row item at
position P in the RecyclerView collection. In the above drawing, for example, the adapter uses the view holder to
lookup the references for the ImageView and TextView at that position so it doesn't have to repeatedly call
FindViewById for those views as the user scrolls through the collection and reuses views.
When you implement an adapter, you must override the following RecyclerView.Adapter methods:
OnCreateViewHolder – Instantiates the item layout file and view holder.
OnBindViewHolder – Loads the data at the specified position into the views whose references are stored in
the given view holder.
ItemCount – Returns the number of items in the data source.
The layout manager calls these methods while it is positioning items within the RecyclerView .
Notifying RecyclerView of Data Changes
RecyclerView does not automatically update its display when the contents of its data source changes; the adapter
must notify RecyclerView when there is a change in the data set. The data set can change in many ways; for
example, the contents within an item can change or the overall structure of the data may be altered.
RecyclerView.Adapter provides a number of methods that you can call so that RecyclerView responds to data
changes in the most efficient manner:
NotifyItemChanged – Signals that the item at the specified position has changed.
NotifyItemRangeChanged – Signals that the items in the specified range of positions have changed.
NotifyItemInserted – Signals that the item in the specified position has been newly inserted.
NotifyItemRangeInserted – Signals that the items in the specified range of positions have been newly
inserted.
NotifyItemRemoved – Signals that the item in the specified position has been removed.
NotifyItemRangeRemoved – Signals that the items in the specified range of positions have been removed.
NotifyDataSetChanged – Signals that the data set has changed (forces a full update).
If you know exactly how your data set has changed, you can call the appropriate methods above to refresh
RecyclerView in the most efficient manner. If you do not know exactly how your data set has changed, you can call
NotifyDataSetChanged , which is far less efficient because RecyclerView must refresh all the views that are visible to
the user. For more information about these methods, see RecyclerView.Adapter.
In the next topic, A Basic RecyclerView Example, an example app is implemented to demonstrate real code
examples of the parts and functionality outlined above.
Related Links
RecyclerView
A Basic RecyclerView Example
Extending the RecyclerView Example
RecyclerView
A Basic RecyclerView Example
7/13/2018 • 10 minutes to read • Edit Online
To understand how RecyclerView works in a typical application, this topic explores the RecyclerViewer sample
app, a simple code example that uses RecyclerView to display a large collection of photos:
RecyclerViewer uses CardView to implement each photograph item in the RecyclerView layout. Because of
RecyclerView 's performance advantages, this sample app is able to quickly scroll through a large collection of
photos smoothly and without noticeable delays.
An Example Data Source
In this example app, a "photo album" data source (represented by the PhotoAlbum class) supplies RecyclerView
with item content. PhotoAlbum is a collection of photos with captions; when you instantiate it, you get a ready-
made collection of 32 photos:
Each photo instance in PhotoAlbum exposes properties that allow you to read its image resource ID, PhotoID , and
its caption string, Caption . The collection of photos is organized such that each photo can be accessed by an
indexer. For example, the following lines of code access the image resource ID and caption for the tenth photo in
the collection:
int imageId = mPhotoAlbum[9].ImageId;
string caption = mPhotoAlbum[9].Caption;
PhotoAlbum also provides a RandomSwap method that you can call to swap the first photo in the collection with a
randomly-chosen photo elsewhere in the collection:
mPhotoAlbum.RandomSwap ();
Because the implementation details of PhotoAlbum are not relevant to understanding RecyclerView , the
PhotoAlbum source code is not presented here. The source code to PhotoAlbum is available at PhotoAlbum.cs in
the RecyclerViewer sample app.
Layout and Initialization
The layout file, Main.axml, consists of a single RecyclerView within a LinearLayout :
Note that you must use the fully-qualified name android.support.v7.widget.RecyclerView because
RecyclerView is packaged in a support library. The OnCreate method of MainActivity initializes this layout,
instantiates the adapter, and prepares the underlying data source:
This code resides in the main activity's OnCreate method. The constructor to the layout manager requires a
context, so the MainActivity is passed using this as seen above.
Instead of using the the predefind LinearLayoutManager , you can plug in a custom layout manager that displays
two CardView items side-by-side, implementing a page-turning animation effect to traverse through the
collection of photos. Later in this guide, you will see an example of how to modify the layout by swapping in a
different layout manager.
View Holder
The view holder class is called PhotoViewHolder . Each PhotoViewHolder instance holds references to the
ImageView and TextView of an associated row item, which is laid out in a CardView as diagrammed here:
PhotoViewHolder derives from RecyclerView.ViewHolder and contains properties to store references to the
ImageView and TextView shown in the above layout. PhotoViewHolder consists of two properties and one
constructor:
public class PhotoViewHolder : RecyclerView.ViewHolder
{
public ImageView Image { get; private set; }
public TextView Caption { get; private set; }
In this code example, the PhotoViewHolder constructor is passed a reference to the parent item view (the
CardView ) that PhotoViewHolder wraps. Note that you always forward the parent item view to the base
constructor. The PhotoViewHolder constructor calls FindViewById on the parent item view to locate each of its
child view references, ImageView and TextView , storing the results in the Image and Caption properties,
respectively. The adapter later retrieves view references from these properties when it updates this CardView 's
child views with new data.
For more information about RecyclerView.ViewHolder , see the RecyclerView.ViewHolder class reference.
Adapter
The adapter loads each RecyclerView row with data for a particular photograph. For a given photograph at row
position P, for example, the adapter locates the associated data at position P within the data source and copies
this data to the row item at position P in the RecyclerView collection. The adapter uses the view holder to lookup
the references for the ImageView and TextView at that position so it doesn't have to repeatedly call FindViewById
for those views as the user scrolls through the photograph collection and reuses views.
In RecyclerViewer, an adapter class is derived from RecyclerView.Adapter to create PhotoAlbumAdapter :
The mPhotoAlbum member contains the data source (the photo album) that is passed into the constructor; the
constructor copies the photo album into this member variable. The following required RecyclerView.Adapter
methods are implemented:
OnCreateViewHolder – Instantiates the item layout file and view holder.
OnBindViewHolder – Loads the data at the specified position into the views whose references are stored in
the given view holder.
ItemCount – Returns the number of items in the data source.
The layout manager calls these methods while it is positioning items within the RecyclerView . The
implementation of these methods is examined in the following sections.
OnCreateViewHolder
The layout manager calls OnCreateViewHolder when the RecyclerView needs a new view holder to represent an
item. OnCreateViewHolderinflates the item view from the view's layout file and wraps the view in a new
PhotoViewHolder instance. The PhotoViewHolder constructor locates and stores references to child views in the
layout as described previously in View Holder.
Each row item is represented by a CardView that contains an ImageView (for the photo) and a TextView (for the
caption). This layout resides in the file PhotoCardView.axml:
This layout represents a single row item in the RecyclerView . The OnBindViewHolder method (described below )
copies data from the data source into the ImageView and TextView of this layout. OnCreateViewHolder inflates this
layout for a given photo location in the RecyclerView and instantiates a new PhotoViewHolder instance (which
locates and caches references to the ImageView and TextView child views in the associated CardView layout):
The resulting view holder instance, vh , is returned back to the caller (the layout manager).
OnBindViewHolder
When the layout manager is ready to display a particular view in the RecyclerView 's visible screen area, it calls
the adapter's OnBindViewHolder method to fill the item at the specified row position with content from the data
source. OnBindViewHolder gets the photo information for the specified row position (the photo's image resource
and the string for the photo's caption) and copies this data to the associated views. Views are located via
references stored in the view holder object (which is passed in through the holder parameter):
The passed-in view holder object must first be cast into the derived view holder type (in this case,
PhotoViewHolder ) before it is used. The adapter loads the image resource into the view referenced by the view
holder's Image property, and it copies the caption text into the view referenced by the view holder's Caption
property. This binds the associated view with its data.
Notice that OnBindViewHolderis the code that deals directly with the structure of the data. In this case,
OnBindViewHolder understands how to map the RecyclerView item position to its associated data item in the data
source. The mapping is straightforward in this case because the position can be used as an array index into the
photo album; however, more complex data sources may require extra code to establish such a mapping.
ItemCount
The ItemCount method returns the number of items in the data collection. In the example photo viewer app, the
item count is the number of photos in the photo album:
For more information about RecyclerView.Adapter , see the RecyclerView.Adapter class reference.
Putting it All Together
The resulting RecyclerView implementation for the example photo app consists of MainActivity code that
creates the data source, layout manager and the adapter. MainActivity creates the mRecyclerView instance,
instantiates the data source and the adapter, and plugs in the layout manager and adapter:
public class MainActivity : Activity
{
RecyclerView mRecyclerView;
RecyclerView.LayoutManager mLayoutManager;
PhotoAlbumAdapter mAdapter;
PhotoAlbum mPhotoAlbum;
// Plug in my adapter:
mAdapter = new PhotoAlbumAdapter (mPhotoAlbum);
mRecyclerView.SetAdapter (mAdapter);
}
}
When this code is compiled and run, it creates the basic photo viewing app as shown in the following screenshots:
This basic app only supports browsing of the photo album. It does not respond to item-touch events, nor does it
handle changes in the underlying data. This functionality is added in Extending the RecyclerView Example.
Changing the LayoutManager
Because of RecyclerView 's flexibility, it's easy to modify the app to use a different layout manager. In the following
example, it is modified to display the photo album with a grid layout that scrolls horizontally rather than with a
vertical linear layout. To do this, the layout manager instantiation is modified to use the GridLayoutManager as
follows:
This code change replaces the vertical LinearLayoutManager with a GridLayoutManager that presents a grid made
up of two rows that scroll in the horizontal direction. When you compile and run the app again, you'll see that the
photographs are displayed in a grid and that scrolling is horizontal rather than vertical:
By changing only one line of code, is is possible to modify the photo-viewing app to use a different layout with
different behavior. Notice that neither the adapter code nor the layout XML had to be modified to change the
layout style.
In the next topic, Extending the RecyclerView Example, this basic sample app is extended to handle item-click
events and update RecyclerView when the underlying data source changes.
Related Links
RecyclerViewer (sample)
RecyclerView
RecyclerView Parts and Functionality
Extending the RecyclerView Example
RecyclerView
Extending the RecyclerView Example
7/13/2018 • 5 minutes to read • Edit Online
The basic app described in A Basic RecyclerView Example actually doesn't do much – it simply scrolls and displays
a fixed list of photograph items to facilitate browsing. In real-world applications, users expect to be able to interact
with the app by tapping items in the display. Also, the underlying data source can change (or be changed by the
app), and the contents of the display must remain consistent with these changes. In the following sections, you'll
learn how to handle item-click events and update RecyclerView when the underlying data source changes.
Handling Item-Click Events
When a user touches an item in the RecyclerView , an item-click event is generated to notify the app as to which
item was touched. This event is not generated by RecyclerView – instead, the item view (which is wrapped in the
view holder) detects touches and reports these touches as click events.
To illustrate how to handle item-click events, the following steps explain how the basic photo-viewing app is
modified to report which photograph had been touched by the user. When an item-click event occurs in the
sample app, the following sequence takes place:
1. The photograph's CardView detects the item-click event and notifies the adapter.
2. The adapter forwards the event (with item position information) to the activity's item-click handler.
3. The activity's item-click handler responds to the item-click event.
First, an event handler member called ItemClick is added to the PhotoAlbumAdapter class definition:
Next, an item-click event handler method is added to MainActivity . This handler briefly displays a toast that
indicates which photograph item was touched:
Next, a line of code is needed to register the OnItemClick handler with PhotoAlbumAdapter . A good place to do
this is immediately after PhotoAlbumAdapter is created:
In this basic example, handler registration takes place in the main activity's OnCreate method, but a production
app might register the handler in OnResume and unregister it in OnPause – see Activity Lifecycle for more
information.
PhotoAlbumAdapter will now call OnItemClick when it receives an item-click event. The next step is to create a
handler in the adapter that raises this ItemClick event. The following method, OnClick , is added immediately
after the adapter's ItemCount method:
This OnClick method is the adapter's listener for item-click events from item views. Before this listener can be
registered with an item view (via the item view's view holder), the PhotoViewHolder constructor must be modified
to accept this method as an additional argument, and register OnClick with the item view Click event. Here's
the modified PhotoViewHolder constructor:
The itemView parameter contains a reference to the CardView that was touched by the user. Note that the view
holder base class knows the layout position of the item ( CardView ) that it represents (via the LayoutPosition
property), and this position is passed to the adapter's OnClick method when an item-click event takes place. The
adapter's OnCreateViewHolder method is modified to pass the adapter's OnClick method to the view -holder's
constructor:
Now when you build and run the sample photo-viewing app, tapping a photo in the display will cause a toast to
appear that reports which photograph was touched:
This example demonstrates just one approach for implementing event handlers with RecyclerView . Another
approach that could be used here is to place events on the view holder and have the adapter subscribe to these
events. If the sample photo app provided a photo editing capability, separate events would be required for the
ImageView and the TextView within each CardView : touches on the TextView would launch an EditView dialog
that lets the user edit the caption, and touches on the ImageView would launch a photo touchup tool that lets the
user crop or rotate the photo. Depending on the needs of your app, you must design the best approach for
handling and responding to touch events.
To demonstrate how RecyclerView can be updated when the data set changes, the sample photo-viewing app can
be modified to randomly pick a photo in the data source and swap it with the first photo. First, a Random Pick
button is added to the example photo app's Main.axml layout:
Next, code is added at the end of the main activity's OnCreate method to locate the Random Pick button in the
layout and attach a handler to it:
Button randomPickBtn = FindViewById<Button>(Resource.Id.randPickButton);
randomPickBtn.Click += delegate
{
if (mPhotoAlbum != null)
{
// Randomly swap a photo with the first photo:
int idx = mPhotoAlbum.RandomSwap();
}
};
This handler calls the photo album's RandomSwap method when the Random Pick button is tapped. The
RandomSwap method randomly swaps a photo with the first photo in the data source, then returns the index of the
randomly-swapped photo. When you compile and run the sample app with this code, tapping the Random Pick
button does not result in a display change because the RecyclerView is not aware of the change to the data
source.
To keep RecyclerView updated after the data source changes, the Random Pick click handler must be modified
to call the adapter's NotifyItemChanged method for each item in the collection that has changed (in this case, two
items have changed: the first photo and the swapped photo). This causes RecyclerView to update its display so
that it is consistent with the new state of the data source:
randomPickBtn.Click += delegate
{
if (mPhotoAlbum != null)
{
int idx = mPhotoAlbum.RandomSwap();
Now, when the Random Pick button is tapped, RecyclerView updates the display to show that a photo further
down in the collection has been swapped with the first photo in the collection:
Of course, NotifyDataSetChanged could have been called instead of making the two calls to NotifyItemChanged ,
but doing so would force RecyclerView to refresh the entire collection even though only two items in the
collection had changed. Calling NotifyItemChanged is significantly more efficient than calling
NotifyDataSetChanged .
Related Links
RecyclerViewer (sample)
RecyclerView
RecyclerView Parts and Functionality
A Basic RecyclerView Example
RecyclerView
ListView
5/2/2018 • 6 minutes to read • Edit Online
ListView is an important UI component of Android applications; it is used everywhere from short lists of menu
options to long lists of contacts or internet favorites. It provides a simple way to present a scrolling list of rows that
can either be formatted with a built-in style or customized extensively.
Overview
List views and adapters are included in the most fundamental building blocks of Android Applications. The
ListView class provides a flexible way to present data, whether it is a short menu or a long scrolling list. It
provides usability features like fast scrolling, indexes and single or multiple selection to help you build mobile-
friendly user interfaces for your applications. A ListView instance requires an Adapter to feed it with data
contained in row views.
This guide explains how to implement ListView and the various Adapter classes in Xamarin.Android. It also
demonstrates how to customize the appearance of a ListView , and it discusses the importance of row re-use to
reduce memory consumption. There is also some discussion of how the Activity Lifecycle affects ListView and
Adapter use. If you are working on cross-platform applications with Xamarin.iOS, the ListView control is
structurally similar to the iOS UITableView (and the Android Adapter is similar to the UITableViewSource ).
First, a short tutorial introduces the ListView with a basic code example. Next, links to more advanced topics are
provided to help you use ListView in real-world apps.
NOTE
The RecyclerView widget is a more advanced and flexible version of ListView . Because RecyclerView is designed to
be the successor to ListView (and GridView ), we recommend that you use RecyclerView rather than ListView for
new app development. For more information, see RecyclerView.
ListView Tutorial
ListView is a ViewGroup that creates a list of scrollable items. The list items are automatically inserted to the list
using a IListAdapter .
In this tutorial, you'll create a scrollable list of country names that are read from a string array. When a list item is
selected, a toast message will display the position of the item in the list.
Start a new project named HelloListView.
Create an XML file named list_item.xml and save it inside the Resources/Layout/ folder. Insert the following:
This file defines the layout for each item that will be placed in the ListView .
Open MainActivity.cs and modify the class to extend ListActivity (instead of Activity ):
ListView.TextFilterEnabled = true;
Notice that this does not load a layout file for the Activity (which you usually do with SetContentView(int) ).
Instead, setting the ListAdapter property automatically adds a ListView to fill the entire screen of the
ListActivity . This method takes an ArrayAdapter<T> , which manages the array of list items that will be placed
into the ListView . The ArrayAdapter<T> constructor takes the application Context , the layout description for
each list item (created in the previous step), and a T[] or Java.Util.IList<T> array of objects to insert in the
ListView (defined next).
The TextFilterEnabled property turns on text filtering for the ListView , so that when the user begins typing, the
list will be filtered.
The ItemClick event can be used to subscribe handlers for clicks. When an item in the ListView is clicked, the
handler is called and a Toast message is displayed, using the text from the clicked item.
You can use list item designs provided by the platform instead of defining your own layout file for the
ListAdapter . For example, try using Android.Resource.Layout.SimpleListItem1 instead of
Resource.Layout.list_item .
using System;
This is the array of strings that will be placed into the ListView .
Run the application. You can scroll the list, or type to filter it, then click an item to see a message. You should see
something like this:
Note that using a hard-coded string array is not the best design practice. One is used in this tutorial for simplicity,
to demonstrate the ListView widget. The better practice is to reference a string array defined by an external
resource, such as with a string-array resource in your project Resources/Values/Strings.xml file. For example:
To use these resource strings for the ArrayAdapter , replace the original ListAdapter line with the following:
Summary
This set of topics introduced ListView and provided some examples of how to use the built-in features of the
ListActivity . It discussed custom implementations of ListView that allowed for colorful layouts and using an
SQLite database, and it briefly touched on the relevance of the activity lifecycle on your ListView
implementation.
Related Links
AccessoryViews (sample)
BasicTableAndroid (sample)
BasicTableAdapter (sample)
BuiltInViews (sample)
CustomRowView (sample)
FastScroll (sample)
SectionIndex (sample)
SimpleCursorTableAdapter (sample)
CursorTableAdapter (sample)
Activity Lifecycle Tutorial
Working with Tables and Cells (in Xamarin.iOS )
ListView Class Reference
ListActivity Class Reference
BaseAdapter Class Reference
ArrayAdapter Class Reference
CursorAdapter Class Reference
ListView Parts and Functionality
4/12/2018 • 2 minutes to read • Edit Online
Overview
A ListView consists of the following parts:
Rows – The visible representation of the data in the list.
Adapter – A non-visual class that binds the data source to the list view.
Fast Scrolling – A handle that lets the user scroll the length of the list.
Section Index – A user interface element that floats over the scrolling rows to indicate where in the list the
current rows are located.
These screenshots use a basic ListView control to show how Fast Scrolling and Section Index are rendered:
The elements that make up a ListView are described in more detail below:
Rows
Each row has its own View . The view can be either one of the built-in views defined in Android.Resources , or a
custom view. Each row can use the same view layout or they can all be different. There are examples in this
document of using built-in layouts and others explaining how to define custom layouts.
Adapter
The ListView control requires an Adapter to supply the formatted View for each row. Android has built-in
Adapters and Views that can be used, or custom classes can be created.
Fast Scrolling
When a ListView contains many rows of data fast-scrolling can be enabled to help the user navigate to any part of
the list. The fast-scrolling 'scroll bar' can be optionally enabled (and customized in API level 11 and higher).
Section Index
While scrolling through long lists, the optional section index provides the user with feedback on what part of the
list they are currently viewing. It is only appropriate on long lists, typically in conjunction with fast scrolling.
Classes Overview
The primary classes used to display ListViews are shown here:
BaseAdapter – Base class for Adapter implementations to bind a ListView to a data source.
ArrayAdapter – Built-in Adapter class that binds an array of strings to a ListView for display. The generic
ArrayAdapter<T> does the same for other types.
This document contains simple examples that use an ArrayAdapter as well as more complex examples that require
custom implementations of BaseAdapter or CursorAdapter .
Populating a ListView With Data
4/12/2018 • 6 minutes to read • Edit Online
Overview
To add rows to a ListView you need to add it to your layout and implement an IListAdapter with methods that
the ListView calls to populate itself. Android includes built-in ListActivity and ArrayAdapter classes that you
can use without defining any custom layout XML or code. The ListActivity class automatically creates a
ListView and exposes a ListAdapter property to supply the row views to display via an adapter.
The built-in adapters take a view resource ID as a parameter that gets used for each row. You can use built-in
resources such as those in Android.Resource.Layout so you don't need to write your own.
Now the user can touch a row and a Toast alert will appear:
Implementing a ListAdapter
ArrayAdapter<string> is great because of its simplicity, but it's extremely limited. However, often times you have a
collection of business entities, rather than just strings that you want to bind. For example, if your data consists of a
collection of Employee classes, then you might want the list to just display the names of each employee. To
customize the behavior of a ListView to control what data is displayed you must implement a subclass of
BaseAdapter overriding the following four items:
Count – To tell the control how many rows are in the data.
GetView – To return a View for each row, populated with data. This method has a parameter for the
ListView to pass in an existing, unused row for re-use.
GetItemId – Return a row identifier (typically the row number, although it can be any long value that you
like).
this[int] indexer – To return the data associated with a particular row number.
The example code in BasicTableAdapter/HomeScreenAdapter.cs demonstrates how to subclass BaseAdapter :
public class HomeScreenAdapter : BaseAdapter<string> {
string[] items;
Activity context;
public HomeScreenAdapter(Activity context, string[] items) : base() {
this.context = context;
this.items = items;
}
public override long GetItemId(int position)
{
return position;
}
public override string this[int position] {
get { return items[position]; }
}
public override int Count {
get { return items.Length; }
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
View view = convertView; // re-use an existing view, if one is available
if (view == null) // otherwise create a new one
view = context.LayoutInflater.Inflate(Android.Resource.Layout.SimpleListItem1, null);
view.FindViewById<TextView>(Android.Resource.Id.Text1).Text = items[position];
return view;
}
}
Because this example uses the same row layout ( SimpleListItem1 ) the resulting application will look identical to
the previous example.
Row View Re -Use
In this example there are only six items. Since the screen can fit eight, no row re-use required. When displaying
hundreds or thousands of rows, however, it would be a waste of memory to create hundreds or thousands of
View objects when only eight fit on the screen at a time. To avoid this situation, when a row disappears from the
screen its view is placed in a queue for re-use. As the user scrolls, the ListView calls GetView to request new
views to display – if available it passes an unused view in the convertView parameter. If this value is null then your
code should create a new view instance, otherwise you can re-set the properties of that object and re-use it.
The GetView method should follow this pattern to re-use row views:
Custom adapter implementations should always re-use the convertView object before creating new views to
ensure they do not run out of memory when displaying long lists.
Some adapter implementations (such as the CursorAdapter ) don't have a GetView method, rather they require
two different methods NewView and BindView which enforce row re-use by separating the responsibilities of
GetView into two methods. There is a CursorAdapter example later in the document.
Causing the fast scrolling handle to appear is as simple as setting the FastScrollEnabled property to true :
ListView.FastScrollEnabled = true;
With the data structures created, the ISectionIndexer methods are very simple:
Your section index titles don't need to map 1:1 to your actual sections. This is why the GetPositionForSection
method exists. GetPositionForSection gives you an opportunity to map whatever indices are in your index list to
whatever sections are in your list view. For example, you may have a "z" in your index, but you may not have a
table section for every letter, so instead of "z" mapping to 26, it may map to 25 or 24, or whatever section index "z"
should map to.
Related Links
BasicTableAndroid (sample)
BasicTableAdapter (sample)
FastScroll (sample)
Customizing a ListView's Appearance
6/4/2018 • 9 minutes to read • Edit Online
Overview
The appearance of a ListView is dictated by the layout of the rows being displayed. To change the appearance of a
ListView , use a different row layout.
The view's properties can then be set by referencing the standard control identifiers Text1 , Text2 and Icon
under Android.Resource.Id (do not set properties that the view does not contain or an exception will be thrown):
view.FindViewById<TextView>(Android.Resource.Id.Text1).Text = item.Heading;
view.FindViewById<TextView>(Android.Resource.Id.Text2).Text = item.SubHeading;
view.FindViewById<ImageView>(Android.Resource.Id.Icon).SetImageResource(item.ImageResourceId); // only use
with ActivityListItem
The properties for the group view and the child view can then be set by referencing the standard Text1 and
Text2 control identifiers as shown above. The SimpleExpandableListItem screenshot (shown above) provides an
example of a one-line group view (SimpleExpandableListItem1) and a two-line child view
(SimpleExpandableListItem2). Alternately, the group view can be configured for two lines
(SimpleExpandableListItem2) and the child view can be configured for one line (SimpleExpandableListItem1), or
both group view and child view can have the same number of lines.
Accessories
Rows can have accessories added to the right of the view to indicate selection state:
SimpleListItemChecked – Creates a single-selection list with a check as the indicator.
SimpleListItemSingleChoice – Creates radio-button-type lists where only one choice is possible.
SimpleListItemMultipleChoice – Creates checkbox-type lists where multiple choices are possible.
The aforementioned accessories are illustrated in the following screens, in their respective order:
To display one of these accessories pass the required layout resource ID to the adapter then manually set the
selection state for the required rows. This line of code shows how to create and assign an Adapter using one of
these layouts:
The ListView itself supports different selection modes, regardless of the accessory being displayed. To avoid
confusion, use Single selection mode with SingleChoice accessories and the Checked or Multiple mode with
the MultipleChoice style. The selection mode is controlled by the ChoiceMode property of the ListView .
Handling API Level
Earlier versions of Xamarin.Android implemented enumerations as integer properties. The latest version has
introduced proper .NET enumeration types which makes it much easier to discover the potential options.
Depending on which API level you are targeting, ChoiceMode is either an integer or an enumeration. The sample
file AccessoryViews/HomeScreen.cs has a block commented out if you wish to target the Gingerbread API:
// For targeting Gingerbread the ChoiceMode is an int, otherwise it is an
// enumeration.
lv.ChoiceMode = Android.Widget.ChoiceMode.Single; // 1
//lv.ChoiceMode = Android.Widget.ChoiceMode.Multiple; // 2
//lv.ChoiceMode = Android.Widget.ChoiceMode.None; // 0
The code also needs to detect single selections differently from multiple selections. To determine which row has
been selected in Single mode use the CheckedItemPosition integer property:
FindViewById<ListView>(Android.Resource.Id.List).CheckedItemPosition
To determine which rows have been selected in Multiple mode you need to loop through the
CheckedItemPositions SparseBooleanArray . A sparse array is like a dictionary that only contains entries where the
value has been changed, so you must traverse the entire array looking for true values to know what has been
selected in the list as illustrated in the following code snippet:
These changes are detailed below, starting with creating the activity's view and the custom row view and then
covering the modifications to the Adapter and Activity to render them.
Adding a ListView to an Activity Layout
Because HomeScreen no longer inherits from ListActivity it doesn't have a default view, so a layout AXML file
must be created for the HomeScreen's view. For this example, the view will have a heading (using a TextView ) and
a ListView to display data. The layout is defined in the Resources/Layout/HomeScreen.axml file which is
shown here:
The benefit of using an Activity with a custom layout (instead of a ListActivity ) lies in being able to add
additional controls to the screen, such as the heading TextView in this example.
Creating a Custom Row Layout
Another AXML layout file is required to contain the custom layout for each row that will appear in the list view. In
this example the row will have a green background, brown text and right-aligned image. The Android XML markup
to declare this layout is described in Resources/Layout/CustomView.axml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#FFDAFF7F"
android:padding="8dp">
<LinearLayout android:id="@+id/Text"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="10dip">
<TextView
android:id="@+id/Text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF7F3300"
android:textSize="20dip"
android:textStyle="italic"
/>
<TextView
android:id="@+id/Text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14dip"
android:textColor="#FF267F00"
android:paddingLeft="100dip"
/>
</LinearLayout>
<ImageView
android:id="@+id/Image"
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="5dp"
android:src="@drawable/icon"
android:layout_alignParentRight="true" />
</RelativeLayout >
While a custom row layout can contain many different controls, scrolling performance can be affected by complex
designs and using images (especially if they have to be loaded over the network). See Google's article for more
information on addressing scrolling performance issues.
Referencing a Custom Row View
The implementation of the custom adapter example is in HomeScreenAdapter.cs . The key method is GetView where
it loads the custom AXML using the resource ID Resource.Layout.CustomView , and then sets properties on each of
the controls in the view before returning it. The complete adapter class is shown:
public class HomeScreenAdapter : BaseAdapter<TableItem> {
List<TableItem> items;
Activity context;
public HomeScreenAdapter(Activity context, List<TableItem> items)
: base()
{
this.context = context;
this.items = items;
}
public override long GetItemId(int position)
{
return position;
}
public override TableItem this[int position]
{
get { return items[position]; }
}
public override int Count
{
get { return items.Count; }
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var item = items[position];
View view = convertView;
if (view == null) // no view to re-use, create new
view = context.LayoutInflater.Inflate(Resource.Layout.CustomView, null);
view.FindViewById<TextView>(Resource.Id.Text1).Text = item.Heading;
view.FindViewById<TextView>(Resource.Id.Text2).Text = item.SubHeading;
view.FindViewById<ImageView>(Resource.Id.Image).SetImageResource(item.ImageResourceId);
return view;
}
}
ListView listView;
The class must then load the Activity's custom layout AXML using the SetContentView method. It can then find the
ListView control in the layout then creates and assigns the adapter and assigns the click handler. The code for the
OnCreate method is shown here:
Finally the ItemClick handler must be defined; in this case it just displays a Toast message:
android:background="#FFDAFF7F"
To re-enable the highlight behavior, and also to customize the color that is used, set the background attribute to a
custom selector instead. The selector will declare both the default background color as well as the highlight color.
The file Resources/Drawable/CustomSelector.xml contains the following declaration:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false"
android:state_selected="false"
android:drawable="@color/cellback" />
<item android:state_pressed="true" >
<shape>
<gradient
android:startColor="#E77A26"
android:endColor="#E77A26"
android:angle="270" />
</shape>
</item>
<item android:state_selected="true"
android:state_pressed="false"
android:drawable="@color/cellback" />
</selector>
To reference the custom selector, change the background attribute in CustomView.axml to:
android:background="@drawable/CustomSelector"
A selected row and the corresponding Toast message now looks like this:
Preventing Flickering on Custom Layouts
Android attempts to improve the performance of ListView scrolling by caching layout information. If you have
long scrolling lists of data you should also set the the android:cacheColorHint property on the ListView
declaration in the Activity's AXML definition (to the same color value as your custom row layout's background).
Failure to include this hint could result in a 'flicker' as the user scrolls through a list with custom row background
colors.
Related Links
BuiltInViews (sample)
AccessoryViews (sample)
CustomRowView (sample)
Using CursorAdapters
4/12/2018 • 5 minutes to read • Edit Online
Overview
Android provides adapter classes specifically to display data from an SQLite database query:
SimpleCursorAdapter – Similar to an ArrayAdapter because it can be used without subclassing. Simply provide
the required parameters (such as a cursor and layout information) in the constructor and then assign to a
ListView .
CursorAdapter – A base class that you can inherit from when you need more control over the binding of data
values to layout controls (for example, hiding/showing controls or changing their properties).
Cursor adapters provide a high-performance way to scroll through long lists of data that are stored in SQLite. The
consuming code must define an SQL query in a Cursor object and then describe how to create and populate the
views for each row.
The VegetableDatabaseclass will be instantiated in the OnCreate method of the HomeScreen activity. The
SQLiteOpenHelper base class manages the setup of the database file and ensures that the SQL in its OnCreate
method is only run once. This class is used in the following two examples for SimpleCursorAdapter and
CursorAdapter .
The cursor query must have an integer column _id for the CursorAdapter to work. If the underlying table does
not have an integer column named _id then use a column alias for another unique integer in the RawQuery that
makes up the cursor. Refer to the Android docs for further information.
Creating the Cursor
The examples use a RawQuery to turn an SQL query into a Cursor object. The column list that is returned from the
cursor defines the data columns that are available for display in the cursor adapter. The code that creates the
database in the SimpleCursorTableAdapter/HomeScreen.cs OnCreate method is shown here:
Any code that calls StartManagingCursor should also call StopManagingCursor . The examples use OnCreate to start,
and OnDestroy to close the cursor. The OnDestroy method contains this code:
StopManagingCursor(cursor);
cursor.Close();
Once an application has a SQLite database available and has created a cursor object as shown, it can utilize either a
SimpleCursorAdapter or a subclass of CusorAdapter to display rows in a ListView .
Using SimpleCursorAdapter
SimpleCursorAdapter is like the ArrayAdapter , but specialized for use with SQLite. It does not require subclassing –
just set some simple parameters when creating the object and then assign it to a ListView ’s Adapter property.
The parameters for the SimpleCursorAdapter constructor are:
Context – A reference to the containing Activity.
Layout – The resource ID of the row view to use.
ICursor – A cursor containing the SQLite query for the data to display.
From string array – An array of strings corresponding to the names of columns in the cursor.
To integer array – An array of layout IDs that correspond to the controls in the row layout. The value of the column
specified in the from array will be bound to the ControlID specified in this array at the same index.
The from and to arrays must have the same number of entries because they form a mapping from the data
source to the layout controls in the view.
The SimpleCursorTableAdapter/HomeScreen.cs sample code wires up a SimpleCursorAdapter like this:
SimpleCursorAdapter is a fast and simple way to display SQLite data in a ListView . The main limitation is that it
can only bind column values to display controls, it does not allow you to change other aspects of the row layout
(for example, showing/hiding controls or changing properties).
Subclassing CursorAdapter
A CursorAdapter subclass has the same performance benefits as the SimpleCursorAdapter for displaying data from
SQLite, but it also gives you complete control over the creation and layout of each row view. The CursorAdapter
implementation is very different from subclassing BaseAdapter because it does not override GetView , GetItemId ,
Count or this[] indexer.
Given a working SQLite database, you only need to override two methods to create a CursorAdapter subclass:
BindView – Given a view, update it to display the data in the provided cursor.
NewView – Called when the ListView requires a new view to display. The CursorAdapter will take care of
recycling views (unlike the GetView method on regular Adapters).
The adapter subclasses in earlier examples have methods to return the number of rows and to retrieve the current
item – the CursorAdapter does not require these methods because that information can be gleaned from the
cursor itself. By splitting the creation and population of each view into these two methods, the CursorAdapter
enforces view re-use. This is in contrast to a regular adapter where it’s possible to ignore the convertView
parameter of the BaseAdapter.GetView method.
Implementing the CursorAdapter
The code in CursorTableAdapter/HomeScreenCursorAdapter.cs contains a CursorAdapter subclass. It stores a
context reference passed into the constructor so that it can access a LayoutInflater in the NewView method. The
complete class looks like this:
The OnDestroy method contains the StopManagingCursor method call described previously.
Related Links
SimpleCursorTableAdapter (sample)
CursorTableAdapter (sample)
Using a ContentProvider
4/12/2018 • 2 minutes to read • Edit Online
CursorAdapters can also be used to display data from a ContentProvider. ContentProviders allow you to access
data exposed by other applications (including Android system data like contacts, media and calendar information).
The preferred way to access a ContentProvider is with a CursorLoader using the LoaderManager. LoaderManager
was introduced in Android 3.0 (API Level 11, Honeycomb) to move blocking tasks off the main thread, and using a
CursorLoader allows the data to be loaded in a thread before being bound to a ListView for display.
Refer to Intro to ContentProviders for more information.
ListView and the Activity Lifecycle
4/12/2018 • 2 minutes to read • Edit Online
Activities go through certain states as your application runs, such as starting up, running, being paused and being
stopped. For more information, and specific guidelines on handling state transitions, see the Activity Lifecycle
Tutorial. It is important to understand the activity lifecycle and place your ListView code in the correct locations.
All of the examples in this document perform 'setup tasks' in the Activity's OnCreate method and (when required)
perform 'teardown' in OnDestroy . The examples generally use small data sets that do not change, so re-loading the
data more frequently is unnecessary.
However, if your data is frequently changing or uses a lot of memory it might be appropriate to use different
lifecycle methods to populate and refresh your ListView . For example, if the underlying data is constantly
changing (or may be affected by updates on other activities) then creating the adapter in OnStart or OnResume will
ensure the latest data is displayed each time the Activity is shown.
If the Adapter uses resources like memory, or a managed cursor, remember to release those resources in the
complementary method to where they were instantiated (eg. objects created in OnStart can be disposed of in
OnStop ).
Configuration Changes
It's important to remember that configuration changes – especially screen rotation and keyboard visibility – can
cause the current activity to be destroyed and re-created (unless you specify otherwise using the
ConfigurationChanges attribute). This means that under normal conditions, rotating a device will cause a ListView
and Adapter to be re-created and (unless you have written code in OnPause and OnResume ) the scroll position and
row selection states will be lost.
The following attribute would prevent an activity from being destroyed and recreated as a result of configuration
changes:
[Activity(ConfigurationChanges="keyboardHidden|orientation")]
The Activity should then override OnConfigurationChanged to respond to those changes appropriately. For more
details on how to handle configuration changes see the documentation.
GridView
4/12/2018 • 3 minutes to read • Edit Online
GridView is a ViewGroup that displays items in a two-dimensional, scrollable grid. The grid items are automatically
inserted to the layout using a ListAdapter .
In this tutorial, you'll create a grid of image thumbnails. When an item is selected, a toast message will display the
position of the image.
Start a new project named HelloGridView.
Find some photos you'd like to use, or download these sample images. Add the image files to the project's
Resources/Drawable directory. In the Properties window, set the Build Action for each to AndroidResource.
Open the Resources/Layout/Main.axml file and insert the following:
This GridView will fill the entire screen. The attributes are rather self explanatory. For more information about
valid attributes, see the GridView reference.
Open HelloGridView.cs and insert the following code for the OnCreate() method:
SetContentView (Resource.Layout.Main);
After the Main.axml layout is set for the content view, the GridView is captured from the layout with
FindViewById . The Adapter property is then used to set a custom adapter ( ImageAdapter ) as the source for all
items to be displayed in the grid. The ImageAdapter is created in the next step.
To do something when an item in the grid is clicked, an anonymous delegate is subscribed to the ItemClick event.
It shows a Toast that displays the index position (zero-based) of the selected item (in a real world scenario, the
position could be used to get the full sized image for some other task). Note that Java-style listener classes can be
used instead of .NET events.
Create a new class called ImageAdapter that subclasses BaseAdapter :
imageView.SetImageResource (thumbIds[position]);
return imageView;
}
First, this implements some required methods inherited from BaseAdapter . The constructor and the Count
property are self-explanatory. Normally, GetItem(int) should return the actual object at the specified position in
the adapter, but it's ignored for this example. Likewise, GetItemId(int) should return the row id of the item, but it's
not needed here.
The first method necessary is GetView() . This method creates a new View for each image added to the
ImageAdapter . When this is called, a View is passed in, which is normally a recycled object (at least after this has
been called once), so there's a check to see if the object is null. If it is null, an ImageView is instantiated and
configured with desired properties for the image presentation:
LayoutParams sets the height and width for the View —this ensures that, no matter the size of the drawable,
each image is resized and cropped to fit in these dimensions, as appropriate.
SetScaleType() declares that images should be cropped toward the center (if necessary).
SetPadding(int, int, int, int) defines the padding for all sides. (Note that, if the images have different
aspect-ratios, then less padding will cause for more cropping of the image if it does not match the
dimensions given to the ImageView.)
If the View passed to GetView() is not null, then the local ImageView is initialized with the recycled View object.
At the end of the GetView() method, the position integer passed into the method is used to select an image from
the thumbIds array, which is set as the image resource for the ImageView .
All that's left is to define the thumbIds array of drawable resources.
Run the application. Your grid layout should look something like this:
Try experimenting with the behaviors of the GridView and ImageView elements by adjusting their properties. For
example, instead of using LayoutParams try using SetAdjustViewBounds() .
References
GridView
ImageView
BaseAdapter .
Portions of this page are modifications based on work created and shared by the Android Open Source Project
and used according to terms described in the Creative Commons 2.5 Attribution License.
GridLayout
4/12/2018 • 3 minutes to read • Edit Online
The GridLayout is a new ViewGroup subclass that supports laying out views in a 2D grid, similar to an HTML
table, as shown below:
GridLayout works with a flat-view hierarchy, where child views set their locations in the grid by specifying the
rows and columns they should be in. This way, the GridLayout is able to position views in the grid without
requiring that any intermediate views provide a table structure, such as seen in the table rows used in the
TableLayout. By maintaining a flat hierarchy, GridLayout is able to more swiftly layout its child views. Let’s take a
look at an example to illustrate what this concept actually means in code.
The layout will adjust the row and column sizes so that the cells can fit their content, as illustrated by the following
diagram:
This results in the following user interface when run in an application:
Specifying Orientation
Notice in the XML above, each TextView does not specify a row or column. When these are not specified, the
GridLayout assigns each child view in order, based upon the orientation. For example, let’s change the
GridLayout’s orientation from the default, which is horizontal, to vertical like this:
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:rowCount="2"
android:columnCount="2"
android:orientation="vertical">
</GridLayout>
Now, the GridLayout will position the cells from top to bottom in each column, instead of left to right, as shown
below:
Specifying spacing
We have a couple of options that will provide spacing between the child views of the GridLayout . We can use the
layout_margin attribute to set the margin on each child view directly, as shown below
<TextView
android:text="Cell 0"
android:textSize="14dip"
android:layout_row="0"
android:layout_column="0"
android:layout_margin="10dp" />
Additionally, in Android 4, a new general-purpose spacing view called Space is now available. To use it, simply add
it as a child view. For example, the XML below adds an additional row to the GridLayout by setting its rowcount to
3, and adds a Space view that provides spacing between the TextViews .
<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:rowCount="3"
android:columnCount="2"
android:orientation="vertical">
<TextView
android:text="Cell 0"
android:textSize="14dip"
android:layout_row="0"
android:layout_column="0" />
<TextView
android:text="Cell 1"
android:textSize="14dip"
android:layout_row="0"
android:layout_column="1" />
<Space
android:layout_row="1"
android:layout_column="0"
android:layout_width="50dp"
android:layout_height="50dp" />
<TextView
android:text="Cell 2"
android:textSize="14dip"
android:layout_row="2"
android:layout_column="0" />
<TextView
android:text="Cell 3"
android:textSize="14dip"
android:layout_row="2"
android:layout_column="1" />
</GridLayout>
This will result in the first column of the GridLayout being stretched to accommodate the size of the button, as we
see here:
To keep the first column from stretching, we can set the button to span two columns by setting its columnspan like
this:
<Button
android:id="@+id/myButton"
android:text="@string/hello"
android:layout_row="3"
android:layout_column="0"
android:layout_columnSpan="2" />
Doing this results in a layout for the TextViews that is similar to the layout we had earlier, with the button added to
the bottom of the GridLayout as shown below:
Related Links
GridLayoutDemo (sample)
Introducing Ice Cream Sandwich
Android 4.0 Platform
Tabbed Layouts
5/12/2018 • 2 minutes to read • Edit Online
Overview
Tabs are a popular user interface pattern in mobile applications because of their simplicity and usability. They
provide a consistent, easy way to navigate between various screens in an application. Android has several API's for
tabbed interfaces:
ActionBar – This is part of a new set of API's that was introduced in Android 3.0 (API level 11) with goal of
providing a consistent navigation and view -switching interface. It has been back ported to Android 2.2 (API
level 8) with the Android Support Library v7.
PagerTabStrip – Indicates the current, next, and previous pages of a ViewPager . ViewPager is available
only via Android Support Library v4. For more information about PagerTabStrip , see ViewPager.
Toolbar – Toolbar is a newer and more flexible action bar component that replaces ActionBar . Toolbar is
available in Android 5.0 Lollipop or later, and it is also available for older versions of Android via the
Android Support Library v7 NuGet package. Toolbar is currently the recommended action bar component
to use in Android apps. For more information, see Toolbar.
Related Links
Material Design - Tabs- ActionBar
Android Support Library v7 AppCompat NuGet Package
v7 appcompat library
Tabbed Layouts with the ActionBar
4/26/2018 • 5 minutes to read • Edit Online
This guide introduces and explains how to use the ActionBar APIs to create a tabbed user interface in a
Xamarin.Android application.
Overview
The action bar is an Android UI pattern that is used to provide a consistent user interface for key features such as
tabs, application identity, menus, and search. In Android 3.0 (API level 11), Google introduced the ActionBar APIs
to the Android platform. The ActionBar APIs introduce UI themes to provide a consistent look and feel and classes
that allow for tabbed user interfaces. This guide discusses how to add Action Bar tabs to a Xamarin.Android
application. It also discusses how to use the Android Support Library v7 to backport ActionBar tabs to
Xamarin.Android applications targeting Android 2.1 to Android 2.3.
Note that Toolbar is a newer and more generalized action bar component that you should use instead of of
ActionBar ( Toolbar was designed to replace ActionBar ). For more information, see Toolbar.
Requirements
Any Xamarin.Android application that targets API level 11 (Android 3.0) or higher has access to the ActionBar APIs
as a part of the native Android APIs.
Some of the ActionBar APIs have been back ported to API level 7 (Android 2.1) and are available via the V7
AppCompat Library, which is made available to Xamarin.Android apps via the Xamarin Android Support Library -
V7 package.
When the ActionBar can't display all of the tabs, it will set up the tabs in a horizontally scrollable view. The user may
swipe left or right to see the remaining tabs. This screenshot from Google Play shows an example of this:
Each tab in the action bar should be associated with a fragment. When the user selects a tab, the application will
display the fragment that is associated with the tab. The ActionBar is not responsible for displaying the appropriate
fragment to the user. Instead, the ActionBar will notify an application about state changes in a tab through a class
that implements the ActionBar.ITabListener interface. This interface provides three callback methods that Android
will invoke when the state of the tab changes:
OnTabSelected - This method is called when the user selects the tab. It should display the fragment.
OnTabReselected - This method is called when the tab is already selected but is selected again by the user.
This callback is typically used to refresh/update the displayed fragment.
OnTabUnselected - This method is called when the user selects another tab. This callback is used to save
the state in the displayed fragment before it disappears.
Xamarin.Android wraps the ActionBar.ITabListener with events on the ActionBar.Tab class. Applications may
assign event handlers to one or more of these events. There are three events (one for each method in
ActionBar.ITabListener ) that an action bar tab will raise:
TabSelected
TabReselected
TabUnselected
Adding Tabs to the ActionBar
The ActionBar is native to Android 3.0 (API level 11) and higher and is available to any Xamarin.Android
application that targets this API as a minimum.
The following steps illustrate how to add ActionBar tabs to an Android Activity:
1. In the OnCreate method of an Activity – before initializing any UI widgets – an application must set the
NavigationMode on the ActionBar to ActionBar.NavigationModeTabs as shown in this code snippet:
ActionBar.NavigationMode = ActionBarNavigationMode.Tabs;
SetContentView(Resource.Layout.Main);
The following code is one example of using these steps to add tabs to an application that uses event handlers to
respond to state changes:
protected override void OnCreate(Bundle bundle)
{
ActionBar.NavigationMode = ActionBarNavigationMode.Tabs;
SetContentView(Resource.Layout.Main);
tab = ActionBar.NewTab();
tab.SetText(Resources.GetString(Resource.String.tab2_text));
tab.SetIcon(Resource.Drawable.tab2_icon);
tab.TabSelected += (sender, args) => {
// Do something when tab is selected
};
ActionBar.AddTab(tab);
}
An Activity may obtain a reference to its ActionBar from the ActionBarActivity.SupportingActionBar property. The
following code snippet illustrates an example of setting up the ActionBar in an Activity:
[Activity(Label = "@string/app_name", Theme = "@style/Theme.AppCompat", MainLauncher = true, Icon =
"@drawable/ic_launcher")]
public class MainActivity : ActionBarActivity, ActionBar.ITabListener
{
static readonly string Tag = "ActionBarTabsSupport";
Summary
In this guide we discussed how to create a tabbed user interface in a Xamarin.Android using the ActionBar. We
covered how to add tabs to the ActionBar and how an Activity can interact with tab events via the
ActionBar.ITabListener interface. We also saw how the Android Support Library v7 AppCompat package
backports the ActionBar tabs to older versions of Android.
Related Links
ActionBarTabs (sample)
Toolbar
Fragments
ActionBar
ActionBarActivity
Action Bar Pattern
Android v7 AppCompat
Xamarin.Android Support Library v7 AppCompat NuGet Package
Android Controls (Widgets)
5/2/2018 • 2 minutes to read • Edit Online
Xamarin.Android exposes all of the native user interface controls (widgets) provided by Android. These controls
can be easily added to Xamarin.Android apps using the Android Designer or programatically via XML layout files.
Regardless of which method you choose, Xamarin.Android exposes all of the user interface object properties and
methods in C#. The following sections introduce the most common Android user interface controls and explain
how to incorporate them into Xamarin.Android apps.
Action Bar
ActionBar is a toolbar that displays the activity title, navigation interfaces, and other interactive items. Typically, the
action bar appears at the top of an activity's window.
Auto Complete
AutoCompleteTextView is an editable text view element that shows completion suggestions automatically while the
user is typing. The list of suggestions is displayed in a drop down menu from which the user can choose an item to
replace the content of the edit box with.
Buttons
Buttons are UI elements that the user taps to perform an action.
Calendar
The Calendar class is used for converting a specific instance in time (a millisecond value that is offset from the
epoch) to values such as year, month, hour, day of the month, and the date of the next week. Calendar supports a
wealth of interaction options with calendar data, including the ability to read and write events, attendees, and
reminders. By using the calendar provider in your application, data you add through the API will appear in the
built-in calendar app that comes with Android.
CardView
CardView is a UI component that presents text and image content in views that resemble cards. CardView is
implemented as a FrameLayout widget with rounded corners and a shadow. Typically, a CardView is used to
present a single row item in a ListView or GridView view group.
Edit Text
EditText is a UI element that is used for entering and modifying text.
Gallery
Gallery is a layout widget that is used to display items in a horizontally scrolling list; it positions the current
selection at the center of the view.
Navigation Bar
The Navigation Bar provides navigation controls on devices that do not include hardware buttons for Home,
Back, and Menu.
Pickers
Pickers are UI elements that allow the user to pick a date or a time by using dialogs that are provided by Android.
Popup Menu
PopupMenu is used for displaying popup menus that are attached to a particular view.
Spinner
Spinner is a UI element that provides a quick way to select one value from a set. It is simmilar to a drop-down list.
Switch
Switch is a UI element that allows a user to toggle between two states, such as ON or OFF. The Switch default
value is OFF.
TextureView
TextureView is a view that uses hardware-accelerated 2D rendering to enable a video or OpenGL content stream
to be displayed.
ToolBar
The Toolbar widget (introduced in Android 5.0 Lollipop) can be thought of as a generalization of the action bar
interface – it is intended to replace the action bar. The Toolbar can be used anywhere in an app layout, and it is
much more customizable than an action bar.
ViewPager
The ViewPager is a layout manager that allows the user to flip left and right through pages of data.
WebView
WebView is a UI element that allows you to create your own window for viewing web pages (or even develop a
complete browser).
ActionBar
4/12/2018 • 3 minutes to read • Edit Online
Overview
When using TabActivity , the code to create the tab icons has no effect when run against the Android 4.0
framework. Although functionally it works as it did in versions of Android prior to 2.3, the TabActivity class itself
has been deprecated in 4.0. A new way to create a tabbed interface has been introduced that uses the Action Bar,
which we'll discuss next.
To create tabs in the Action Bar, we first need to set its NavigationMode property to support tabs. In Android 4, an
ActionBar property is available on the Activity class, which we can use to set the NavigationMode like this:
this.ActionBar.NavigationMode = ActionBarNavigationMode.Tabs;
Once this is done, we can create a tab by calling the NewTab method on the Action Bar. With this tab instance, we
can call the SetText and SetIcon methods to set the tab's label text and icon; these calls are made in order in the
code shown below:
Before we can add the tab however, we need to handle the TabSelected event. In this handler, we can create the
content for the tab. Action Bar tabs are designed to work with Fragments, which are classes that represent a
portion of the user interface in an Activity. For this example, the Fragment's view contains a single TextView ,
which we inflate in our Fragment subclass like this:
var sampleTextView =
view.FindViewById<TextView> (Resource.Id.sampleTextView);
sampleTextView.Text = "sample fragment text";
return view;
}
}
The event argument passed in the TabSelected event is of type TabEventArgs , which includes a
FragmentTransaction property that we can use to add the fragment as shown below:
Finally, we can add the tab to the Action Bar by calling the AddTab method as shown in this code:
this.ActionBar.AddTab (tab);
For the complete example, see the HelloTabsICS project in the sample code for this document.
ShareActionProvider
The ShareActionProvider class enables a sharing action to take place from an Action Bar. It takes care of creating
an action view with a list of apps that can handle a sharing Intent and keeps a history of the previously used
applications for easy access to them later from the Action Bar. This allows applications to share data via a user
experience that's consistent throughout Android.
Image Sharing Example
For example, below is a screenshot of an Action Bar with a menu item to share an image (taken from the
ShareActionProvider sample). When the user taps the menu item on the Action Bar, the ShareActionProvider
loads the application to handle an Intent that is associated with the ShareActionProvider . In this example, the
messaging application has been previously used, so it is presented on the Action Bar.
When the user clicks on the item in the Action Bar, the messaging app that contains the shared image is launched,
as shown below:
Specifying the action Provider Class
To use the ShareActionProvider , set the android:actionProviderClass attribute on a menu item in the XML for the
Action Bar's menu as follows:
Intent CreateIntent ()
{
var sendPictureIntent = new Intent (Intent.ActionSend);
sendPictureIntent.SetType ("image/*");
var uri = Android.Net.Uri.FromFile (GetFileStreamPath ("monkey.png"));
sendPictureIntent.PutExtra (Intent.ExtraStream, uri);
return sendPictureIntent;
}
The image in the code example above is included as an asset with the application and copied to a publicly
accessible location when the Activity is created, so it will be accessible to other applications, such as the messaging
app. The sample code that accompanies this article contains the full source of this example, illustrating its use.
Related Links
Hello Tabs ICS (sample)
ShareActionProvider Demo (sample)
Introducing Ice Cream Sandwich
Android 4.0 Platform
Auto Complete
4/12/2018 • 4 minutes to read • Edit Online
Overview
To create a text entry widget that provides auto-complete suggestions, use the AutoCompleteTextView widget.
Suggestions are received from a collection of strings associated with the widget through an ArrayAdapter .
In this tutorial, you will create a AutoCompleteTextView widget that provides suggestions for a country name.
Tutorial
Start a new project named HelloAutoComplete.
Create an XML file named list_item.xml and save it inside the Resources/Layout folder. Set the Build Action of
this file to AndroidResource . Edit the file to look like this:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dp"
android:textSize="16sp"
android:textColor="#000">
</TextView>
This file defines a simple TextView that will be used for each item that appears in the list of suggestions.
Open Resources/Layout/Main.axml and insert the following:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Country" />
<AutoCompleteTextView android:id="@+id/autocomplete_country"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"/>
</LinearLayout>
Open MainActivity.cs and insert the following code for the OnCreate() method:
textView.Adapter = adapter;
}
After the content view is set to the main.xml layout, the AutoCompleteTextView widget is captured from the layout
with FindViewById . A new ArrayAdapter is then initialized to bind the list_item.xml layout to each list item in the
COUNTRIES string array (defined in the next step). Finally, SetAdapter() is called to associate the ArrayAdapter with
the AutoCompleteTextView widget so that the string array will populate the list of suggestions.
Inside the MainActivity class, add the string array:
static string[] COUNTRIES = new string[] {
"Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
"Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
"Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
"Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
"Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
"Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory",
"British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burundi",
"Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
"Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
"Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
"Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic",
"Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
"East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
"Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
"Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
"French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
"Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
"Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
"Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
"Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
"Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
"Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
"Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
"Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
"Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
"Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
"Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
"Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
"Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
"Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
"Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
"Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
"Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
"Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
"Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
"The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
"Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
"Ukraine", "United Arab Emirates", "United Kingdom",
"United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
"Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
"Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
};
This is the list of suggestions that will be provided in a drop-down list when the user types into the
AutoCompleteTextView widget.
Run the application. As you type, you should see something like this:
More Information
Note that using a hard-coded string array is not a recommended design practice because your application code
should focus on behavior, not content. Application content such as strings should be externalized from the code to
make modifications to the content easier and facilitate localization of the content. The hard-coded strings are used
in this tutorial only to make it simple and focus on the AutoCompleteTextView widget. Instead, your application
should declare such string arrays in an XML file. This can be done with a <string-array> resource in your project
res/values/strings.xml file. For example:
To use these resource strings for the ArrayAdapter , replace the original ArrayAdapter constructor line with the
following:
References
ArrayAdapter
AutoCompleteTextView
Portions of this page are modifications based on work created and shared by the Android Open Source Project
and used according to terms described in the Creative Commons 2.5 Attribution License . This tutorial is based on
the Android Auto Complete tutorial .
Buttons in Xamarin.Android
5/2/2018 • 2 minutes to read • Edit Online
The Button class is used to represent various different styles of button in Android screens. This section introduces
the different options for working with buttons in Xamarin.Android:
RadioButton allows the user to select one option from a set.
ToggleButton allow the user to flip (toggle) a setting between two states.
CheckBox is a special type of button that can be either checked or unchecked to indicate one of two possible
states.
You can also create a custom button that uses an image instead of text.
RadioButton
4/12/2018 • 2 minutes to read • Edit Online
In this section, you will create two mutually-exclusive radio buttons (enabling one disables the other), using the
RadioGroup and RadioButton widgets. When either radio button is pressed, a toast message will be displayed.
Open the Resources/layout/Main.axml file and add two RadioButton s, nested in a RadioGroup (inside the
LinearLayout ):
<RadioGroup
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RadioButton android:id="@+id/radio_red"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Red" />
<RadioButton android:id="@+id/radio_blue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Blue" />
</RadioGroup>
It's important that the RadioButton s are grouped together by the RadioGroup element so that no more than one
can be selected at a time. This logic is automatically handled by the Android system. When one RadioButton within
a group is selected, all others are automatically deselected.
To do something when each RadioButton is selected, we need to write an event handler:
First, the sender that is passed in is cast into a RadioButton. Then a Toast message displays the selected radio
button's text.
Now, at the bottom of the OnCreate() method, add the following:
radio_red.Click += RadioButtonClick;
radio_blue.Click += RadioButtonClick;
This captures each of the RadioButton s from the layout and adds the newly-created event handlerto each.
Run the application.
Tip: If you need to change the state yourself (such as when loading a saved CheckBoxPreference ), use the Checked
property setter or Toggle() method.
Portions of this page are modifications based on work created and shared by the Android Open Source Project
and used according to terms described in the Creative Commons 2.5 Attribution License.
ToggleButton
4/12/2018 • 2 minutes to read • Edit Online
In this section, you'll create a button used specifically for toggling between two states, using the ToggleButton
widget. This widget is an excellent alternative to radio buttons if you have two simple states that are mutually
exclusive ("on" and "off", for example). Android 4.0 (API level 14) introduced an alternative to the toggle button
known as a Switch .
An example of a ToggleButton can be seen in the left hand pair of images, while the right hand pair of images
presents an example of a Switch:
Which control an application uses is a matter of style. Both widgets are functionally equivalent.
Open the Resources/layout/Main.axml file and add the ToggleButton element (inside the LinearLayout ):
To do something when the state is changed, add the following code to the end of the OnCreate() method:
This captures the ToggleButton element from the layout, and handles the Click event, which defines the action to
perform when the button is clicked. In this example, the method checks the new state of the button, then shows a
Toast message that indicates the current state.
Notice that the ToggleButton handles its own state change between checked and unchecked, so you just ask which
it is.
Run the application.
Tip: If you need to change the state yourself (such as when loading a saved CheckBoxPreference ), use the Checked
property setter or Toggle() method.
Related Links
ToggleButton
Switch
CheckBox
4/12/2018 • 2 minutes to read • Edit Online
In this section, you will create a checkbox for selecting items, using the CheckBox widget. When the checkbox is
pressed, a toast message will indicate the current state of the checkbox.
Open the Resources/layout/Main.axml file and add the CheckBox element (inside the LinearLayout ):
<CheckBox android:id="@+id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="check it out" />
To do something when the state is changed, add the following code to the end of the OnCreate() method:
This captures the CheckBox element from the layout, then handles the Click event, which defines the action to be
made when the checkbox is clicked. When clicked, the Checked property is called to check the new state of the
check box. If it has been checked, then a Toast displays the message "Selected", otherwise it displays "Not
selected". The CheckBox handles its own state changes, so you only need to query the current state.
Run it.
Tip: If you need to change the state yourself (such as when loading a saved CheckBoxPreference , use the Checked
property setter or Toggle() method.
Portions of this page are modifications based on work created and shared by the Android Open Source Project
and used according to terms described in the Creative Commons 2.5 Attribution License.
Custom Button
4/12/2018 • 2 minutes to read • Edit Online
In this section, you will create a button with a custom image instead of text, using the Button widget and an XML
file that defines three different images to use for the different button states. When the button is pressed, a short
message will be displayed.
Right-click and download the three images below, then copy them to the Resources/drawable directory of your
project. These will be used for the different button states.
Create a new file in the Resources/drawable directory named android_button.xml. Insert the following XML:
This defines a single drawable resource, which will change its image based on the current state of the button. The
first <item> defines android_pressed.png as the image when the button is pressed (it's been activated); the
second <item> defines android_focused.png as the image when the button is focused (when the button is
highlighted using the trackball or directional pad); and the third <item> defines android_normal.png as the
image for the normal state (when neither pressed nor focused). This XML file now represents a single drawable
resource and when referenced by a Button for its background, the image displayed will change based on these
three states.
NOTE
The order of the <item> elements is important. When this drawable is referenced, the <item> s are traversed in-order to
determine which one is appropriate for the current button state. Because the "normal" image is last, it is only applied when
the conditions android:state_pressed and android:state_focused have both evaluated false.
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:background="@drawable/android_button" />
The android:background attribute specifies the drawable resource to use for the button background (which, when
saved at Resources/drawable/android.xml, is referenced as @drawable/android ). This replaces the normal
background image used for buttons throughout the system. In order for the drawable to change its image based
on the button state, the image must be applied to the background.
To make the button do something when pressed, add the following code at the end of the OnCreate() method:
This captures the Button from the layout, then adds a Toast message to be displayed when the Button is clicked.
Now run the application.
Portions of this page are modifications based on work created and shared by the Android Open Source Project
and used according to terms described in the Creative Commons 2.5 Attribution License.
Calendar
4/12/2018 • 7 minutes to read • Edit Online
Calendar API
A new set of calendar APIs introduced in Android 4 supports applications that are designed to read or write data
to the calendar provider. These APIs support a wealth of interaction options with calendar data, including the
ability to read and write events, attendees, and reminders. By using the calendar provider in your application, data
you add through the API will appear in the built-in calendar app that comes with Android 4.
Adding Permissions
When working with the new calendar APIs in your application, the first thing you need to do is add the appropriate
permissions to the Android manifest. The permissions you need to add are android.permisson.READ_CALENDAR and
android.permission.WRITE_CALENDAR , depending on whether you are reading and/or writing calendar data.
Listing Calendars
First, let's examine how to enumerate the calendars that have been registered in the calendar app. To do this, we
can instantiate a CursorLoader . Introduced in Android 3.0 (API 11), CursorLoader is the preferred way to consume
a ContentProvider . At a minimum, we'll need to specify the content Uri for calendars and the columns we want to
return; this column specification is known as a projection.
Calling the CursorLoader.LoadInBackground method allows us to query a content provider for data, such as the
calendar provider. LoadInBackground performs the actual load operation and returns a Cursor with the results of
the query.
The CalendarContract assists us in specifying both the content Uri and the projection. To get the content Uri for
querying calendars, we can simply use the CalendarContract.Calendars.ContentUri property like this:
Using the CalendarContract to specify which calendar columns we want is equally simple. We just add fields in the
CalendarContract.Calendars.InterfaceConsts class to an array. For example, the following code includes the
calendar's ID, display name, and account name:
string[] calendarsProjection = {
CalendarContract.Calendars.InterfaceConsts.Id,
CalendarContract.Calendars.InterfaceConsts.CalendarDisplayName,
CalendarContract.Calendars.InterfaceConsts.AccountName
};
The Id is important to include if you are using a SimpleCursorAdapter to bind the data to the UI, as we will see
shortly. With the content Uri and projection in place, we instantiate the CursorLoader and call the
CursorLoader.LoadInBackground method to return a cursor with the calendar data as shown below:
The UI for this example contains a ListView , with each item in the list representing a single calendar. The
following XML shows the markup that includes the ListView :
Also, we need to specify the UI for each list item, which we place in a separate XML file as follows:
From this point on, it's just normal Android code to bind the data from the cursor to the UI. We'll use a
SimpleCursorAdapter as follows:
string[] sourceColumns = {
CalendarContract.Calendars.InterfaceConsts.CalendarDisplayName,
CalendarContract.Calendars.InterfaceConsts.AccountName };
int[] targetResources = {
Resource.Id.calDisplayName, Resource.Id.calAccountName };
ListAdapter = adapter;
In the above code, the adapter takes the columns specified in the sourceColumns array and writes them to the user
interface elements in the targetResources array for each calendar entry in the cursor. The Activity used here is a
subclass of ListActivity ; it includes the ListAdapter property to which we set the adapter.
Here's a screenshot showing the end result, with the calendar info displayed in the ListView :
cursor.MoveToPosition(i);
int calId =
cursor.GetInt (cursor.GetColumnIndex (calendarsProjection [0]));
In this code, we're creating an Intent to open an Activity of type EventListActivity , passing the calendar's ID in the
Intent. We will need the ID to know which calendar to query for events. In the EventListActivity 's OnCreate
method, we can retrieve the ID from the Intent as shown below:
Now let's query events for this calendar ID. The process to query for events is similar to the way we queried for a
list of calendars earlier, only this time we'll work with the CalendarContract.Events class. The following code
creates a query to retrieve events:
string[] eventsProjection = {
CalendarContract.Events.InterfaceConsts.Id,
CalendarContract.Events.InterfaceConsts.Title,
CalendarContract.Events.InterfaceConsts.Dtstart
};
In this code, we first get the content Uri for events from the CalendarContract.Events.ContentUri property. Then
we specify the event columns we want to retrieve in the eventsProjection array. Finally, we instantiate a
CursorLoader with this information and call the loader's LoadInBackground method to return a Cursor with the
event data.
To display the event data in the UI, we can use markup and code just like we did before to display the list of
calendars. Again, we use SimpleCursorAdapter to bind the data to a ListView as shown in the following code:
string[] sourceColumns = {
CalendarContract.Events.InterfaceConsts.Title,
CalendarContract.Events.InterfaceConsts.Dtstart };
int[] targetResources = {
Resource.Id.eventTitle,
Resource.Id.eventStartDate };
The main difference between this code and the code that we used earlier to show the calendar list is the use of a
ViewBinder , which is set on the line:
adapter.ViewBinder = new ViewBinder ();
The ViewBinder class allows us to further control how we bind values to views. In this case, we use it to convert
the event start time from milliseconds to a date string, as shown in the following implementation:
return true;
}
return false;
}
}
eventValues.Put (CalendarContract.Events.InterfaceConsts.CalendarId,
_calId);
eventValues.Put (CalendarContract.Events.InterfaceConsts.Title,
"Test Event from M4A");
eventValues.Put (CalendarContract.Events.InterfaceConsts.Description,
"This is an event created from Xamarin.Android");
eventValues.Put (CalendarContract.Events.InterfaceConsts.Dtstart,
GetDateTimeMS (2011, 12, 15, 10, 0));
eventValues.Put (CalendarContract.Events.InterfaceConsts.Dtend,
GetDateTimeMS (2011, 12, 15, 11, 0));
eventValues.Put(CalendarContract.Events.InterfaceConsts.EventTimezone,
"UTC");
eventValues.Put(CalendarContract.Events.InterfaceConsts.EventEndTimezone,
"UTC");
Note that if we do not set the time zone, an exception of type Java.Lang.IllegalArgumentException will be thrown.
Because event time values must be expressed in milliseconds since epoch, we create a GetDateTimeMS method (in
EventListActivity ) to convert our date specifications into millisecond format:
long GetDateTimeMS (int yr, int month, int day, int hr, int min)
{
Calendar c = Calendar.GetInstance (Java.Util.TimeZone.Default);
return c.TimeInMillis;
}
If we add a button to the event list UI and run the above code in the button's click event handler, the event is added
to the calendar and updated in our list as shown below:
If we open the calendar app, then we will see that the event is written there as well:
As you can see, Android allows powerful and easy access to retrieve and persist calendar data, allowing
applications to seamlessly integrate calendar capabilities.
Related Links
Calendar Demo (sample)
Introducing Ice Cream Sandwich
Android 4.0 Platform
CardView
4/12/2018 • 8 minutes to read • Edit Online
The Cardview widget is a UI component that presents text and image content in views that resemble cards. This
guide explains how to use and customize CardView in Xamarin.Android applications while maintaining
backward compatibility with earlier versions of Android.
Overview
The Cardview widget, introduced in Android 5.0 (Lollipop), is a UI component that presents text and image
content in views that resemble cards. CardView is implemented as a FrameLayout widget with rounded corners
and a shadow. Typically, a CardView is used to present a single row item in a ListView or GridView view group.
For example, the following screen shot is an example of a travel reservation app that implements CardView -based
travel destination cards in a scrollable ListView :
This guide explains how to add the CardView package to your Xamarin.Android project, how to add CardView to
your layout, and how to customize the appearance of CardView in your app. In addition, this guide provides a
detailed list of CardView attributes that you can change, including attributes to help you use CardView on
versions of Android earlier than Android 5.0 Lollipop.
Requirements
The following is required to use new Android 5.0 and later features (including CardView ) in Xamarin-based apps:
Xamarin.Android – Xamarin.Android 4.20 or later must be installed and configured with either Visual
Studio or Visual Studio for Mac.
Android SDK – Android 5.0 (API 21) or later must be installed via the Android SDK Manager.
Java JDK 1.8 – JDK 1.7 can be used if you are specifically targetting API level 23 and earlier. JDK 1.8 is
available from Oracle.
Your app must also include the Xamarin.Android.Support.v7.CardView package. To add the
Xamarin.Android.Support.v7.CardView package in Visual Studio for Mac:
1. Open your project, right-click Packages and select Add Packages.
2. In the Add Packages dialog, search for CardView.
3. Select Xamarin Support Library v7 CardView, then click Add Package.
To add the Xamarin.Android.Support.v7.CardView package in Visual Studio:
1. Open your project, right-click the References node (in the Solution Explorer pane) and select Manage
NuGet Packages....
2. When the Manage NuGet Packages dialog is displayed, enter CardView in the search box.
3. When Xamarin Support Library v7 CardView appears, click Install.
To learn how to configure an Android 5.0 app project, see Setting Up an Android 5.0 Project. For more
information about installing NuGet packages, see Walkthrough: Including a NuGet in your project.
Introducing CardView
The default CardView resembles a white card with minimally rounded corners and a slight shadow. The following
example Main.axml layout displays a single CardView widget that contains a TextView :
If you use this XML to replace the existing contents of Main.axml, be sure to comment out any code in
MainActivity.cs that refers to resources in the previous XML.
This layout example creates a default CardView with a single line of text as shown in the following screen shot:
In this example, the app style is set to the light Material Theme ( Theme.Material.Light ) so that the CardView
shadows and edges are easier to see. For more information about theming Android 5.0 apps, see Material Theme.
In the next section, we'll learn how to customize CardView for an application.
Customizing CardView
You can modify the basic CardView attributes to customize the appearance of the CardView in your app. For
example, the elevation of the CardView can be increased to cast a larger shadow (which makes the card seem to
float higher above the background). Also, the corner radius can be increased to make the corners of the card more
rounded.
In the next layout example, a customized CardView is used to create a simulation of a print photograph (a
"snapshot"). An ImageView is added to the CardView for displaying the image, and a TextView is positioned
below the ImageView for displaying the title of the image. In this example layout, the CardView has the following
customizations:
The cardElevation is increased to 4dp to cast a larger shadow.
The cardCornerRadius is increased to 5dp to make the corners appear more rounded.
Because CardView is provided by the Android v7 support library, its attributes are not available from the
android: namespace. Therefore, you must define your own XML namespace and use that namespace as the
CardView attribute prefix. In the layout example below, we will use this line to define a namespace called
cardview :
xmlns:cardview="http://schemas.android.com/apk/res-auto"
You can call this namespace card_view or even myapp if you choose (it's accessible only within the scope of this
file). Whatever you choose to call this namespace, you must use it to prefix the CardView attribute that you want
to modify. In this layout example, the cardview namespace is the prefix for cardElevation and cardCornerRadius :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:cardview="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_horizontal"
android:padding="5dp">
<android.support.v7.widget.CardView
android:layout_width="fill_parent"
android:layout_height="245dp"
android:layout_gravity="center_horizontal"
cardview:cardElevation="4dp"
cardview:cardCornerRadius="5dp">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="240dp"
android:orientation="vertical"
android:padding="8dp">
<ImageView
android:layout_width="fill_parent"
android:layout_height="190dp"
android:id="@+id/imageView"
android:scaleType="centerCrop" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="#333333"
android:text="Photo Title"
android:id="@+id/textView"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="5dp" />
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
When this layout example is used to display an image in a photo viewing app, the CardView has the appearance
of a photo snapshot, as depicted in the following screenshot:
This screenshot is taken from the RecyclerViewer sample app, which uses a RecyclerView widget to present a
scrolling list of CardView images for viewing photos. For more information about RecyclerView , see the
RecyclerView guide.
Notice that a CardView can display more than one child view in its content area. For example, in the above photo
viewing app example, the content area is comprised of a ListView that contains an ImageView and a TextView .
Although CardView instances are often arranged vertically, you can also arrange them horizontally (see Creating
a Custom View Style for an example screenshot).
CardView Layout Options
CardView layouts can be customized by setting one or more attributes that affect its padding, elevation, corner
radius, and background color:
Each attribute can also be changed dynamically by calling a counterpart CardView method (for more information
on CardView methods, see the CardView class reference). Note that these attributes (except for background color)
accept a dimension value, which is a decimal number followed by the unit. For example, 11.5dp specifies 11.5
density-independent pixels.
Padding
CardView offers five padding attributes to position content within the card. You can set them in your layout XML
or you can call analogous methods in your code:
Larger values of cardElevation increase the shadow size to make CardView seem to float higher above the
background. The cardElevation attribute also determines the drawing order of overlapping views; that is, the
CardView will be drawn under another overlapping view with a higher elevation setting and above any
overlapping views with a lower elevation setting. The cardMaxElevation setting is useful for when your app
changes elevation dynamically – it prevents the shadow from extending past the limit that you define with this
setting.
Corner Radius and Background Color
CardView offers attributes that you can use to control its corner radius and its background color. These two
properties allow you change the overall style of the CardView :
These attributes are explained as follows:
cardCornerRadius – The corner radius of all corners of the CardView .
cardBackgroundColor – The background color of the CardView .
In this diagram, cardCornerRadius is set to a more rounded 10dp and cardBackgroundColor is set to "#FFFFCC"
(light yellow ).
Compatibility
You can use CardView on versions of Android earlier than Android 5.0 Lollipop. Because CardView is part of the
Android v7 support library, you can use CardView with Android 2.1 (API level 7) and higher. However, you must
install the Xamarin.Android.Support.v7.CardView package as described in Requirements, above.
CardView exhibits slightly different behavior on devices before Lollipop (API level 21):
CardView uses a programmatic shadow implementation that adds additional padding.
CardView does not clip child views that intersect with the CardView 's rounded corners.
To help in managing these compatibility differences, CardView provides several additional attributes that you can
configure in your layout:
cardPreventCornerOverlap – Set this attribute to true to add padding when your app is running on earlier
Android versions API level 20 and earlier). This setting prevents CardView content from intersecting with
(
the CardView 's rounded corners.
cardUseCompatPadding – Set this attribute to true to add padding when your app is running in versions of
Android at or greater than API level 21. If you want to use CardView on pre-Lollipop devices and have it
look the same on Lollipop (or later), set this attribute to true . When this attribute is enabled, CardView
adds additional padding to draw shadows when it runs on pre-Lollipop devices. This helps to overcome the
differences in padding that are introduced when pre-Lollipop programmatic shadow implementations are
in effect.
For more information about maintaining compatibility with earlier versions of Android, see Maintaining
Compatibility.
Summary
This guide introduced the new CardView widget included in Android 5.0 (Lollipop). It demonstrated the default
CardView appearance and explained how to customize CardView by changing its elevation, corner roundness,
content padding, and background color. It listed the CardView layout attributes (with reference diagrams), and
explained how to use CardView on Android devices earlier than Android 5.0 Lollipop. For more information
about CardView , see the CardView class reference.
Related Links
RecyclerView (sample)
Introduction to Lollipop
CardView class reference
Edit Text
4/12/2018 • 2 minutes to read • Edit Online
In this section, you will create a text field for user input, using the EditText widget. Once text has been entered into
the field, the "Enter" key will display the text in a toast message.
Open the Resources\layout\main.xml file and add the EditText element (inside the LinearLayout ):
To do something with the text that the user types, add the following code to the end of the OnCreate method:
This captures the EditText element from the layout and sets a KeyPress handler, which defines the action to be
made when a key is pressed while the widget has focus. In this case, the method is defined to listen for the Enter
key (when pressed down), then pop up a Toast message with the text that has been entered. The Handled
property should always be true if the event has been handled, so that the event doesn't bubble-up (which would
result in a carriage return in the text field).
Run the application.
Portions of this page are modifications based on work created and shared by the Android Open Source Project
and used according to terms described in the Creative Commons 2.5 Attribution License . This tutorial is based on
the Android Form Stuff tutorial .
Related Links
EditTextSample
Gallery
4/12/2018 • 3 minutes to read • Edit Online
Gallery is a layout widget used to display items in a horizontally scrolling list and positions the current selection
at the center of the view.
IMPORTANT
This widget was deprecated in Android 4.1 (API level 16).
In this tutorial, you'll create a gallery of photos and then display a toast message each time a gallery item is
selected.
After the Main.axml layout is set for the content view, the Gallery is captured from the layout with FindViewById .
The Adapter property is then used to set a custom adapter ( ImageAdapter ) as the source for all items to be
displayed in the dallery. The ImageAdapter is created in the next step.
To do something when an item in the gallery is clicked, an anonymous delegate is subscribed to the ItemClick
event. It shows a Toast that displays the index position (zero-based) of theselected item (in a real world scenario,
the position could be used to get the full sized image for some other task).
First, there are a few member variables, including an array of IDs that reference the images saved in the drawable
resources directory (Resources/drawable).
Next is the class constructor, where the Context for an ImageAdapter instance is defined and saved to a local field.
Next, this implements some required methods inherited from BaseAdapter . The constructor and the Count
property are self-explanatory. Normally, GetItem(int) should return the actual object at the specified position in
the adapter, but it's ignored for this example. Likewise, GetItemId(int) should return the row id of the item, but it's
not needed here.
The method does the work to apply an image to an ImageView that will be embedded in the Gallery In this
method, the member Context is used to create a new ImageView . The ImageView is prepared by applying an
image from the local array of drawable resources, setting the Gallery.LayoutParams height and width for the
image, setting the scale to fit the ImageView dimensions, and then finally setting the background to use the
styleable attribute acquired in the constructor.
See ImageView.ScaleType for other image scaling options.
Walkthrough
Start a new project named HelloGallery.
Find some photos you'd like to use, or download these sample images. Add the image files to the project's
Resources/Drawable directory. In the Properties window, set the Build Action for each to AndroidResource.
Open Resources/Layout/Main.axml and insert the following:
Open MainActivity.cs and insert the following code for the OnCreate() method:
i.SetImageResource (thumbIds[position]);
i.LayoutParameters = new Gallery.LayoutParams (150, 100);
i.SetScaleType (ImageView.ScaleType.FitXy);
return i;
}
Portions of this page are modifications based on work created and shared by the Android Open Source Project
and used according to terms described in the Creative Commons 2.5 Attribution License.
Navigation Bar
4/12/2018 • 2 minutes to read • Edit Online
Android 4 introduced a new system user interface feature called a Navigation Bar, which provides navigation
controls on devices that don't include hardware buttons for Home, Back, and Menu. The following screenshot
shows the Navigation Bar from a Nexus Prime device:
Several new flags are available that control the visibility of the Navigation Bar and its controls, as well as the
visibility of the System Bar that was introduced in Android 3. The flags are defined in the Android.View.View class
and are listed below:
SystemUiFlagVisible – Makes the Navigation Bar visible.
SystemUiFlagLowProfile – Dims out controls in the Navigation Bar.
SystemUiFlagHideNavigation – Hides the Navigation Bar.
These flags can be applied to any view in the view hierarchy by setting the SystemUiVisibility property. If
multiple views have this property set, the system combines them with an OR operation and applies them so long
as the window in which the flags are set retains focus. When you remove a view, any flags it has set will also be
removed.
The following example shows a simple application where clicking any of the buttons changes the
SystemUiVisibility :
The code to change the SystemUiVisibility sets the property on a TextView from each button's click event
handler as shown below:
var tv = FindViewById<TextView> (Resource.Id.systemUiFlagTextView);
var lowProfileButton = FindViewById<Button>(Resource.Id.lowProfileButton);
var hideNavButton = FindViewById<Button> (Resource.Id.hideNavigation);
var visibleButton = FindViewById<Button> (Resource.Id.visibleButton);
lowProfileButton.Click += delegate {
tv.SystemUiVisibility =
(StatusBarVisibility)View.SystemUiFlagLowProfile;
};
hideNavButton.Click += delegate {
tv.SystemUiVisibility =
(StatusBarVisibility)View.SystemUiFlagHideNavigation;
};
visibleButton.Click += delegate {
tv.SystemUiVisibility = (StatusBarVisibility)View.SystemUiFlagVisible;
}
tv.SystemUiVisibilityChange +=
delegate(object sender, View.SystemUiVisibilityChangeEventArgs e) {
tv.Text = String.Format ("Visibility = {0}", e.Visibility);
};
Related Links
SystemUIVisibilityDemo (sample)
Introducing Ice Cream Sandwich
Android 4.0 Platform
Pickers
4/12/2018 • 2 minutes to read • Edit Online
Pickers are UI elements that allow the user to pick a date or a time by using dialogs that are provided by Android:
Date Picker is used to select a date (year, month, and day).
Time Picker is used to select a time (hour, minute, and AM/PM ).
Date Picker
7/25/2018 • 4 minutes to read • Edit Online
Overview
There are occasions when a user must input data into an Android application. To assist with this, the Android
framework provides the DatePicker widget and the DatePickerDialog . The DatePicker allows users to select the
year, month, and day in a consistent interface across devices and applications. The DatePickerDialog is a helper
class that encapsulates the DatePicker in a dialog.
Modern Android applications should display the DatePickerDialog in a DialogFragment . This will allow an
application to display the DatePicker as a popup dialog or embedded in an Activity. In addition, the DialogFragment
will manage the lifecycle and display of the dialog, reducing the amount of code that must be implemented.
This guide will demonstrate how to use the DatePickerDialog , wrapped in a DialogFragment . The sample
application will display the DatePickerDialog as a modal dialog when the user clicks a button on an Activity. When
the date is set by the user, a TextView will update with the date that was selected.
Requirements
The sample application for this guide targets Android 4.1 (API level 16) or higher, but is applicable to Android 3.0
(API level 11 or higher). It is possible to support older versions of Android with the addition of the Android
Support Library v4 to the project and some code changes.
public void OnDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth)
{
// Note: monthOfYear is a value between 0 and 11, not 1 and 12!
DateTime selectedDate = new DateTime(year, monthOfYear + 1, dayOfMonth);
Log.Debug(TAG, selectedDate.ToLongDateString());
_dateSelectedHandler(selectedDate);
}
}
The NewInstance method is invoked to instantiate a new DatePickerFragment . This method takes an
Action<DateTime> that will be invoked when the user clicks on the OK button in the DatePickerDialog .
When the fragment is to be displayed, Android will call the method OnCreateDialog . This method will create a new
DatePickerDialog object and initialize it with the current date and the callback object (which is the current instance
of the DatePickerFragment ).
NOTE
Be aware that the value of the month when IOnDateSetListener.OnDateSet is invoked is in the range of 0 to 11, and not
1 to 12. The day of the month will be in the range of 1 to 31 (depending on which month was selected).
_dateDisplay = FindViewById<TextView>(Resource.Id.date_display);
_dateSelectButton = FindViewById<Button>(Resource.Id.date_select_button);
_dateSelectButton.Click += DateSelect_OnClick;
}
Summary
This sample discussed how to display a DatePicker widget as a popup modal dialog as a part of an Android
Activity. It provided a sample DialogFragment implementation and discussed the IOnDateSetListener interface.
This sample also demonstrated how the DialogFragment may interact with the host Activity to display the selected
date.
Related Links
DialogFragment
DatePicker
DatePickerDialog
DatePickerDialog.IOnDateSetListener
Select A Date
Time Picker
7/25/2018 • 7 minutes to read • Edit Online
To provide a way for the user to select a time, you can use TimePicker. Android apps typically use TimePicker with
TimePickerDialog for selecting a time value – this helps to ensure a consistent interface across devices and
applications. TimePicker allows users to select the time of day in either 24-hour or 12-hour AM/PM mode.
TimePickerDialog is a helper class that encapsulates the TimePicker in a dialog.
Overview
Modern Android applications display the TimePickerDialog in a DialogFragment. This makes it possible for an
application to display the TimePicker as a popup dialog or embed it in an Activity. In addition, the DialogFragment
manages the lifecycle and display of the dialog, reducing the amount of code that must be implemented.
This guide demonstrates how to use the TimePickerDialog , wrapped in a DialogFragment . The sample application
displays the TimePickerDialog as a modal dialog when the user clicks a button on an Activity. When the time is set
by the user, the dialog exits and a handler updates a TextView on the Activity screen with the time that was
selected.
Requirements
The sample application for this guide targets Android 4.1 (API level 16) or higher, but is can be used with Android
3.0 (API level 11 or higher). It is possible to support older versions of Android with the addition of the Android
Support Library v4 to the project and some code changes.
When you click the PICK TIME button, the example app launches the TimePickerDialog as seen in this screenshot:
In the TimePickerDialog , selecting a time and clicking the OK button causes the TimePickerDialog to invoke the
method IOnTimeSetListener.OnTimeSet. This interface is implemented by the hosting DialogFragment (
TimePickerFragment , described below ). Clicking the Cancel button causes the fragment and dialog to be dismissed.
DialogFragment returns the selected time to the hosting Actvity in one of three ways:
1. Invoking a method or setting a property – The Activity can provide a property or method specifically for
setting this value.
2. Raising an event – The DialogFragment can define an event that will be raised when OnTimeSet is invoked.
3. Using an Action – The DialogFragment can invoke an Action<DateTime> to display the time in the Activity.
The Activity will provide the Action<DateTime when instantiating the DialogFragment .
This sample will use the third technique, which requires that the Activity supply an Action<DateTime> handler to
the DialogFragment .
This is a basic LinearLayout with a TextView that displays the time and a Button that opens the TimePickerDialog .
Note that this layout uses hard-coded strings and dimensions to make the app simpler and easier to understand –
a production app normally uses resources for these values (as can be seen in the DatePicker code example).
Edit MainActivity.cs and replace its contents with the following code:
using Android.App;
using Android.Widget;
using Android.OS;
using System;
using Android.Util;
using Android.Text.Format;
namespace TimePickerDemo
{
[Activity(Label = "TimePickerDemo", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
TextView timeDisplay;
Button timeSelectButton;
When you build and run this example, you should see an initial screen similar to the following screen shot:
Clicking the PICK TIME button does nothing because the DialogFragment has not yet been implemented to
display the TimePicker . The next step is to create this DialogFragment .
Extending DialogFragment
To extend DialogFragment for use with TimePicker , it is necessary to create a subclass that is derived from
DialogFragmentand implements TimePickerDialog.IOnTimeSetListener . Add the following class to
MainActivity.cs:
This TimePickerFragment class is broken down into smaller pieces and explained in the next section.
DialogFragment Implementation
TimePickerFragment implements several methods: a factory method, a Dialog instantiation method, and the
OnTimeSet handler method required by TimePickerDialog.IOnTimeSetListener .
TAG is initialized for logging purposes (MyTimePickerFragment can be changed to whatever string you
want to use). The timeSelectedHandler Action is initialized to an empty delegate to prevent null reference
exceptions:
The factory method is called to instantiate a new TimePickerFragment . This method takes an
NewInstance
Action<DateTime> handler that is invoked when the user clicks the OK button in the TimePickerDialog :
public static TimePickerFragment NewInstance(Action<DateTime> onTimeSelected)
{
TimePickerFragment frag = new TimePickerFragment();
frag.timeSelectedHandler = onTimeSelected;
return frag;
}
When the fragment is to be displayed, Android calls the DialogFragment method OnCreateDialog. This
method creates a new TimePickerDialog object and initializes it with the Activity, the callback object (which
is the current instance of the TimePickerFragment ), and the current time:
When the user changes the time setting in the TimePicker dialog, the OnTimeSet method is invoked.
OnTimeSet creates a DateTime object using the current date and merges in the time (hour and minute)
selected by the user:
This DateTime object is passed to the timeSelectedHandler that is registered with the TimePickerFragment
object at creation time. OnTimeSet invokes this handler to update the Activity's time display to the selected
time (this handler is implemented in the next section):
timeSelectedHandler (selectedTime);
frag.Show(FragmentManager, TimePickerFragment.TAG);
}
After TimeSelectOnClick instantiates a TimePickerFragment , it creates and passes in a delegate for an anonymous
method that updates the Activity's time display with the passed-in time value. Finally, it launches the TimePicker
dialog fragment (via DialogFragment.Show ) to display the TimePicker to the user.
At the end of the OnCreate method, add the following line to attach the event handler to the PICK TIME button
that launches the dialog:
timeSelectButton.Click += TimeSelectOnClick;
When the PICK TIME button is clicked, TimeSelectOnClick will be invoked to display the TimePicker dialog
fragment to the user.
Try It!
Build and run the app. When you click the PICK TIME button, the TimePickerDialog is displayed in the default
time format for the Activity (in this case, 12-hour AM/PM mode):
When you click OK in the TimePicker dialog, the handler updates the Activity's TextView with the chosen time
and then exits:
Next, add the following line of code to OnCreateDialog immediately after is24HourFormat is declared and
initialized:
is24HourFormat = true;
This change forces the flag passed to the TimePickerDialog constructor to be true so that 24-hour mode is used
instead of the time format of the hosting Activity. When you build and run the app again, click the PICK TIME
button, the TimePicker dialog is now displayed in 24 hour format:
Because the handler calls DateTime.ToShortTimeString to print the time to the Activity's TextView , the time is still
printed in the default 12-hour AM/PM format.
Summary
This article explained how to display a TimePicker widget as a popup modal dialog from an Android Activity. It
provided a sample DialogFragment implementation and discussed the IOnTimeSetListener interface. This sample
also demonstrated how the DialogFragment can interact with the host Activity to display the selected time.
Related Links
DialogFragment
TimePicker
TimePickerDialog
TimePickerDialog.IOnTimeSetListener
TimePickerDemo (sample)
PopUp Menu
4/12/2018 • 2 minutes to read • Edit Online
The PopupMenu class adds support for displaying popup menus that are attached to a particular view. The following
illustration shows a popup menu presented from a button, with the second item highlighted just as it is selected:
Android 4 added a couple of new features to PopupMenu that make it a bit easier to work with, namely:
Inflate – The Inflate method is now available directly on the PopupMenu class.
DismissEvent – The PopupMenu class now has a DismissEvent.
Let's take a look at these improvements. In this example, we have a single Activity that contains a button. When the
user clicks the button, a popup menu is displayed as shown below:
Creating a Popup Menu
When we create an instance of the PopupMenu , we need to pass its constructor a reference to the Context , as well
as the view to which the menu is attached. In this case, we create the PopupMenu in the click event handler for our
button, which is named showPopupMenu . This button is also the view to which we'll attach the PopupMenu , as shown
in the following code:
In Android 3, the code to inflate the menu from an XML resource required that you first get a reference to a
MenuInflator , and then call its Inflate method with the resource ID of the XML that contained the menu and the
menu instance to inflate into. Such an approach still works in Android 4 and later as the code below shows:
As of Android 4 however, you can now call Inflate directly on the instance of the PopupMenu . This makes the code
more concise as shown here:
showPopupMenu.Click += (s, arg) => {
PopupMenu menu = new PopupMenu (this, showPopupMenu);
menu.Inflate (Resource.Menu.popup_menu);
menu.Show ();
};
In the code above, after inflating the menu we simply call menu.Show to display it on the screen.
Related Links
PopupMenuDemo (sample)
Introducing Ice Cream Sandwich
Android 4.0 Platform
Spinner
4/12/2018 • 4 minutes to read • Edit Online
Spinner is a widget that presents a drop-down list for selecting items. This guide explains how to create a simple
app that displays a list of choices in a Spinner, followed by modifications that display other values associated with
the selected choice.
Basic Spinner
In the first part of this tutorial, you'll create a simple spinner widget that displays a list of planets. When a planet is
selected, a toast message displays the selected item:
Notice that the TextView 's android:text attribute and the Spinner 's android:prompt attribute both reference the
same string resource. This text behaves as a title for the widget. When applied to the Spinner , the title text will
appear in the selection dialog that appears upon selecting the widget.
Edit Resources/Values/Strings.xml and modify the file to look like this:
The second <string> element defines the title string referenced by the TextView and Spinner in the layout
above. The <string-array> element defines the list of strings that will be displayed as the list in the Spinner
widget.
Now open MainActivity.cs and add the following using statement:
using System;
adapter.SetDropDownViewResource (Android.Resource.Layout.SimpleSpinnerDropDownItem);
spinner.Adapter = adapter;
}
After the Main.axml layout is set as the content view, the Spinner widget is captured from the layout with
FindViewById<>(int) . The CreateFromResource() method then creates a new ArrayAdapter , which binds each item
in the string array to the initial appearance for the Spinner (which is how each item will appear in the spinner
when selected). The Resource.Array.planets_array ID references the string-array defined above and the
Android.Resource.Layout.SimpleSpinnerItem ID references a layout for the standard spinner appearance, defined by
the platform. SetDropDownViewResource is called to define the appearance for each item when the widget is opened.
Finally, the ArrayAdapter is set to associate all of its items with the Spinner by setting the Adapter property.
Now provide a callback method that notifys the application when an item has been selected from the Spinner .
Here's what this method should look like:
When an item is selected, the sender is cast to a Spinner so that items can be accessed. Using the Position
property on the ItemEventArgs , you can find out the text of the selected object, and use it to display a Toast .
Run the application; it should look like this:
Spinner Using Key/Value Pairs
Often it is necessary to use Spinner to display key values that are associated with some kind of data used by your
app. Because Spinner does not work directly with key/value pairs, you must store the key/value pair separately,
populate the Spinner with key values, then use the position of the selected key in the Spinner to look up the
associated data value.
In the following steps, the HelloSpinner app is modified to display the mean temperature for the selected planet:
Add the following using statement to MainActivity.cs:
using System.Collections.Generic;
Add the following instance variable to the MainActivity class. This list will hold key/value pairs for the planets and
their mean temperatures:
In the OnCreate method, add the following code before adapter is declared:
This code creates a simple store for planets and their associated mean temperatures. (In a real-world app, a
database is typically used to store keys and their associated data.)
Immediately after the above code, add the following lines to extract the keys and put them into a list (in order):
Pass this list to the ArrayAdapter constructor (instead of the planets_array resource):
Modify spinner_ItemSelected so that the selected position is used to look up the value (the temperature)
associated with the selected planet:
Portions of this page are modifications based on work created and shared by the Android Open Source Project
and used according to terms described in the Creative Commons 2.5 Attribution License.
Switch
7/3/2018 • 2 minutes to read • Edit Online
The Switch widget (shown below ) allows a user to toggle between two states, such as ON or OFF. The Switch
default value is OFF. The widget is shown below in both its ON and OFF states:
Creating a Switch
To create a switch, simply declare a Switch element in XML as follows:
<Switch android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Switch android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:textOn="YES"
android:textOff="NO" />
Providing a Title
The Switch widget also supports including a text label by setting the text attribute as follows:
Related Links
SwitchDemo (sample)
Tab Layout Tutorial
TextureView
4/12/2018 • 2 minutes to read • Edit Online
The TextureView class is a view that uses hardware-accelerated 2D rendering to enable a video or OpenGL
content stream to be displayed. For example, the following screenshot shows the TextureView displaying a live
feed from the device's camera:
Unlike the SurfaceView class, which can also be used to display OpenGL or video content, the TextureView is not
rendered into a separate window. Therefore, TextureView is able to support view transformations like any other
view. For example, rotating a TextureView can be accomplished by simply setting its Rotation property, its
transparency by setting its Alpha property, and so on.
Therefore, with the TextureView we can now do things like display a live stream from the camera and transform it,
as shown in the following code:
public class TextureViewActivity : Activity,
TextureView.ISurfaceTextureListener
{
Camera _camera;
TextureView _textureView;
SetContentView (_textureView);
}
try {
_camera.SetPreviewTexture (surface);
_camera.StartPreview ();
} catch (Java.IO.IOException ex) {
Console.WriteLine (ex.Message);
}
The above code creates a TextureView instance in the Activity's OnCreate method and sets the Activity as the
TextureView 's SurfaceTextureListener . To be the SurfaceTextureListener , the Activity implements the
TextureView.ISurfaceTextureListener interface. The system will call the OnSurfaceTextAvailable method when the
SurfaceTexture is ready for use. In this method, we take the SurfaceTexture that is passed in and set it to the
camera's preview texture. Then we are free to perform normal view -based operations, such as setting the
Rotation and Alpha , as in the example above. The resulting application, running on a device, is shown below:
To use the TextureView , hardware acceleration must be enabled, which it will be by default as of API Level 14.
Also, since this example uses the camera, both the android.permission.CAMERA permission and the
android.hardware.camera feature must be set in the AndroidManifest.xml.
Related Links
TextureViewDemo (sample)
Introducing Ice Cream Sandwich
Android 4.0 Platform
Toolbar
4/12/2018 • 2 minutes to read • Edit Online
The Toolbar is an action bar component that provides more flexibility than the default action bar: it can be placed
anywhere in the app, its size can be changed, and it can use a color scheme that is different from the app's theme.
Also, each app screen can have multiple Toolbars.
Overview
A key design element of any Android activity is an action bar. The action bar is the UI component that is used for
navigation, search, menus, and branding in an Android app. In Android versions before Android 5.0 Lollipop, the
action bar (also known as the app bar) was the recommended component for providing this functionality.
The Toolbar widget (introduced in Android 5.0 Lollipop) can be thought of as a generalization of the action bar
interface – it is intended to replace the action bar. The Toolbar can be used anywhere in an app layout, and it is
much more customizable than an action bar. The following screenshot illustrates the customized Toolbar example
created in this guide:
There are some important differences between the Toolbar and the action bar:
A Toolbar can be placed anywhere in the user interface.
Multiple toolbars can be displayed on the same screen.
If fragments are used, each fragment can have its own Toolbar .
A Toolbar can be configured to span only a partial width of the screen.
Because the Toolbar is not bound to the color scheme of the Activity's window decor, it can have a visually
distinct color scheme.
Unlike the action bar, the Toolbar does not include an icon on the left. Its menus on the right use less
space.
The Toolbar height is adjustable.
Other views can be included inside the Toolbar .
Requirements
Toolbar is available on Android 5.0 Lollipop (API 21) and later. When targeting Android releases earlier than
Android 5.0, use the Android Support Library v7 AppCompat, which provides backwards-compatible Toolbar
support in a NuGet package. Toolbar Compatibility explains how to use this library.
Related Links
Lollipop Toolbar (sample)
AppCompat Toolbar (sample)
Replacing the Action Bar
4/12/2018 • 7 minutes to read • Edit Online
Overview
One of the most common uses for the Toolbar is to replace the default action bar with a custom Toolbar (when a
new Android project is created, it uses the default action bar). Because the Toolbar provides the ability to add
branded logos, titles, menu items, navigation buttons, and even custom views to the app bar section of an Activity's
UI, it offers a significant upgrade over the default action bar.
To replace an app's default action bar with a Toolbar :
1. Create a new custom theme and modify the app's properties so that it uses this new theme.
2. Disable the windowActionBar attribute in the custom theme and enable the windowNoTitle attribute.
3. Define a layout for the Toolbar .
4. Include the Toolbar layout in the Activity's Main.axml layout file.
5. Add code to the Activity's OnCreate method to locate the Toolbar and call SetActionBar to install the
ToolBar as the action bar.
The following sections explain this process in detail. A simple app is created and its action bar is replaced with a
customized Toolbar .
This XML defines a new custom theme called MyTheme that is based on the
Theme.Material.Light.DarkActionBar theme in Lollipop. The windowNoTitle attribute is set to true to hide the
title bar:
<item name="android:windowNoTitle">true</item>
<item name="android:windowActionBar">false</item>
An olive-green colorPrimary setting is used for the background color of the toolbar:
<item name="android:colorPrimary">#5A8622</item>
For more information about applying a custom theme to an app, see Using Custom Themes.
This XML defines the custom Toolbar that replaces the default action bar. The minimum height of the Toolbar is
set to the size of the action bar that it replaces:
android:minHeight="?android:attr/actionBarSize"
The background color of the Toolbar is set to the olive-green color defined earlier in styles.xml:
android:background="?android:attr/colorPrimary"
Beginning with Lollipop, the android:theme attribute can be used to style an individual view. The
ThemeOverlay.Material themes introduced in Lollipop make it possible to overlay the default Theme.Material
themes, overwriting relevant attributes to make them either light or dark. In this example, the Toolbar uses a dark
theme so that its contents are light in color:
android:theme="@android:style/ThemeOverlay.Material.Dark.ActionBar"
This setting is used so that menu items contrast with the darker background color.
This layout includes the Toolbar defined in toolbar.xml and uses a RelativeLayout to specify that the Toolbar is
to be placed at the very top of the UI (above the button).
using Android.Views;
Also, add the following lines of code to the end of the OnCreate method:
This code finds the Toolbar and calls SetActionBar so that the Toolbar will take on default action bar
characteristics. The title of the Toolbar is changed to My Toolbar. As seen in this code example, the ToolBar can
be directly referenced as an action bar. Compile and run this app – the customized Toolbar is displayed in place of
the default action bar:
Notice that the Toolbar is styled independently of the Theme.Material.Light.DarkActionBar theme that is applied
to the remainder of the app.
If an exception occurs while running the app, see the Troubleshooting section below.
Android calls the OnCreateOptionsMenu method so that the app can specify the menu resource for an activity. In this
method, the top_menus.xml resource is inflated into the passed menu . This code causes the new Edit, Save, and
Preferences menu items to appear in the Toolbar .
Implement OnOptionsItemSelected
Add the following method to MainActivity.cs:
When a user taps a menu item, Android calls the OnOptionsItemSelected method and passes in the menu item that
was selected. In this example, the implementation just displays a toast to indicate which menu item was tapped.
Build and run ToolbarFun to see the new menu items in the toolbar. The Toolbar now displays three menu icons
as seen in this screenshot:
When a user taps the Edit menu item, a toast is displayed to indicate that the OnOptionsItemSelected method was
called:
When a user taps the overflow menu, the Preferences menu item is displayed. Typically, less-common actions
should be placed in the overflow menu – this example uses the overflow menu for Preferences because it is not
used as often as Edit and Save:
For more information about Android menus, see the Android Developer Menus topic.
Troubleshooting
The following tips can help to debug problems that may occur while replacing the action bar with a toolbar.
Activity Already Has an Action Bar
If the app is not properly configured to use a custom theme as explained in Apply the Custom Theme, the
following exception may occur while running the app:
In addition, an error message such as the following may be produced: Java.Lang.IllegalStateException: This
Activity already has an action bar supplied by the window decor.
To correct this error, verify that the android:theme attribute for the custom theme is added to <application> (in
Properties/AndroidManifest.xml) as described earlier in Apply the Custom Theme. In addition, this error may
be caused if the Toolbar layout or custom theme is not configured properly.
Related Links
Lollipop Toolbar (sample)
AppCompat Toolbar (sample)
Adding a Second Toolbar
4/12/2018 • 4 minutes to read • Edit Online
Overview
The Toolbar can do more than replace the action bar – it can be used multiple times within an Activity, it can be be
customized for placement anywhere on the screen, and it can be configured to span only a partial width of the
screen. The examples below illustrate how to create a second Toolbar and place it at the bottom of the screen. This
Toolbar implements Copy, Cut, and Paste menu items.
This XML adds a second Toolbar to the bottom of the screen with an empty ImageView filling the middle of the
screen. The height of this Toolbar is set to the height of an action bar:
android:minHeight="?android:attr/actionBarSize"
The background color of this Toolbar is set to an accent color that will be defined next:
android:background="?android:attr/colorAccent
Notice that this Toolbar is based on a different theme (ThemeOverlay.Material.Dark.ActionBar) than that
used by the Toolbar created in Replacing the Action Bar – it isn't bound to the Activity's window decor or to the
theme used in the first Toolbar .
Edit Resources/values/styles.xml and add the following accent color to the style definition:
<item name="android:colorAccent">#C7A935</item>
This gives the bottom toolbar a dark amber color. Building and running the app displays a blank second toolbar at
the bottom of the screen:
The following sections demonstrate this process in detail: Cut, Copy, and Paste menu items are added to the
bottom Toolbar .
Define the Edit Menu Resource
In the Resources/menu subdirectory, create a new XML file called edit_menus.xml and replace the contents with
the following XML:
<?xml version="1.0" encoding="utf-8" ?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/menu_cut"
android:icon="@mipmap/ic_menu_cut_holo_dark"
android:showAsAction="ifRoom"
android:title="Cut" />
<item
android:id="@+id/menu_copy"
android:icon="@mipmap/ic_menu_copy_holo_dark"
android:showAsAction="ifRoom"
android:title="Copy" />
<item
android:id="@+id/menu_paste"
android:icon="@mipmap/ic_menu_paste_holo_dark"
android:showAsAction="ifRoom"
android:title="Paste" />
</menu>
This XML creates the Cut, Copy, and Paste menu items (using icons that were added to the mipmap- folders in
Replacing the Action Bar).
Inflate the Menus
At the end of the OnCreate method in MainActivity.cs, add the following lines of code:
This code locates the edit_toolbar view defined in Main.axml, sets its title to Editing, and inflates its menu items
(defined in edit_menus.xml). It defines a menu click handler that displays a toast to indicate which editing icon
was tapped.
Build and run the app. When the app runs, the text and icons added above will appear as shown here:
Tapping the Cut menu icon causes the following toast to be displayed:
The Up Button
Most Android apps rely on the Back button for app navigation; pressing the Back button takes the user to the
previous screen. However, you may also want to provide an Up button that makes it easy for users to navigate "up"
to the app's main screen. When the user selects the Up button, the user moves up to a higher level in the app
hierarchy – that is, the app pops the user back multiple activities in the back stack rather than popping back to the
previously-visited Activity.
To enable the Up button in a second activity that uses a Toolbar as its action bar, call the
SetDisplayHomeAsUpEnabled and SetHomeButtonEnabled methods in the second activity's OnCreate method:
SetActionBar (toolbar);
...
ActionBar.SetDisplayHomeAsUpEnabled (true);
ActionBar.SetHomeButtonEnabled (true);
The Support v7 Toolbar code sample demonstrates the Up button in action. This sample (which uses the
AppCompat library described next) implements a second activity that uses the Toolbar Up button for hierarchical
navigation back to the previous activity. In this example, the DetailActivity home button enables the Up button
by making the following SupportActionBar method calls:
SetSupportActionBar (toolbar);
...
SupportActionBar.SetDisplayHomeAsUpEnabled (true);
SupportActionBar.SetHomeButtonEnabled (true);
When the user navigates from MainActivity to DetailActivity , the DetailActivity displays an Up button (left
pointing arrow ) as shown in the screenshot:
Tapping this Up button causes the app to return to MainActivity . In a more complex app with multiple levels of
hierarchy, tapping this button would return the user to the next highest level in the app rather than to the previous
screen.
Related Links
Lollipop Toolbar (sample)
AppCompat Toolbar (sample)
Toolbar Compatibility
4/12/2018 • 5 minutes to read • Edit Online
Overview
This section explains how to use Toolbar on versions of Android earlier than Android 5.0 Lollipop. If your app
does not support versions of Android earlier than Android 5.0, you can skip this section.
Because Toolbar is part of the Android v7 support library, it can be used on devices running Android 2.1 (API
level 7) and higher. However, the Android Support Library v7 AppCompat NuGet must be installed and the code
modified so that it uses the Toolbar implementation provided in this library. This section explains how to install
this NuGet and modify the ToolbarFun app from Adding a Second Toolbar so that it runs on versions of Android
earlier than Lollipop 5.0.
To modify an app to use the AppCompat version of Toolbar:
1. Set the Minimum and Target Android versions for the app.
2. Install the AppCompat NuGet Package.
3. Use an AppCompat theme instead of a built-in Android theme.
4. Modify MainActivity so that it subclasses AppCompatActivity rather than Activity .
Each of these steps is explained in detail in the following sections.
Update Layouts
Edit Resources/layout/Main.axml and replace the Toolbar element with the following XML:
<android.support.v7.widget.Toolbar
android:id="@+id/edit_toolbar"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorAccent"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Edit Resources/layout/toolbar.xml and replace its contents with the following XML:
Note that the ?attr values are no longer prefixed with android: (recall that the ? notation references a resource
in the current theme). If ?android:attr were still used here, Android would reference the attribute value from the
currently running platform rather than from the AppCompat library. Because this example uses the actionBarSize
defined by the AppCompat library, the android: prefix is dropped. Similarly, @android:style is changed to
@style so that the android:theme attribute is set to a theme in the AppCompat library – the
ThemeOverlay.AppCompat.Dark.ActionBar theme is used here rather than ThemeOverlay.Material.Dark.ActionBar .
The item names and parent theme in this example are no longer prefixed with android: because we are using the
AppCompat library. Also, the parent theme is changed to the AppCompat version of Light.DarkActionBar .
Update Menus
To support earlier versions of Android, the AppCompat library uses custom attributes that mirror the attributes of
the android: namespace. However, some attributes (such as the showAsAction attribute used in the <menu> tag)
do not exist in the Android framework on older devices – showAsAction was introduced in Android API 11 but is
not available in Android API 7. For this reason, a custom namespace must be used to prefix all of the attributes
defined by the support library. In the menu resource files, a namespace called local is defined for prefixing the
showAsAction attribute.
Edit Resources/menu/top_menus.xml and replace its contents with the following XML:
xmlns:local="http://schemas.android.com/apk/res-auto">
The showAsAction attribute is prefaced with this local: namespace rather than android:
local:showAsAction="ifRoom"
Similarly, edit Resources/menu/edit_menus.xml and replace its contents with the following XML:
How does this namespace switch provide support for the showAsAction attribute on Android versions prior to API
Level 11? The custom attribute showAsAction and all of its possible values are included in the app when the
AppCompat NuGet is installed.
Subclass AppCompatActivity
The final step in the conversion is to modify MainActivity so that it is a subclass of AppCompactActivity . Edit
MainActivity.cs and add the following using statements:
using Android.Support.V7.App;
using Toolbar = Android.Support.V7.Widget.Toolbar;
This declares Toolbar to be the AppCompat version of Toolbar . Next, change the class definition of MainActivity
:
To set the action bar to the AppCompat version of Toolbar , substitute the call to SetActionBar with
SetSupportActionBar . In this example, the title is also changed to indicate that the AppCompat version of Toolbar
is being used:
SetSupportActionBar (toolbar);
SupportActionBar.Title = "My AppCompat Toolbar";
Finally, change the Minimum Android level to the pre-Lollipop value that is to be supported (for example, API 19).
Build the app and run it on a pre-Lollipop device or Android emulator. The following screenshot shows the
AppCompat version of ToolbarFun on a Nexus 4 running KitKat (API 19):
When the AppCompat library is used, themes do not have to be switched based on the Android version – the
AppCompat library makes it possible to provide a consistent user experience across all supported Android
versions.
Related Links
Lollipop Toolbar (sample)
AppCompat Toolbar (sample)
ViewPager
4/12/2018 • 3 minutes to read • Edit Online
ViewPager is a layout manager that lets you implement gestural navigation. Gestural navigation allows the user
to swipe left and right to step through pages of data. This guide explains how to implement gestural navigation
with ViewPager, with and without Fragments. It also describes how to add page indicators using PagerTitleStrip
and PagerTabStrip.
Overview
A common scenario in app development is the need to provide users with gestural navigation between sibling
views. In this approach, the user swipes left or right to access pages of content (for example, in a setup wizard or a
slide show ). You can create these swipe views by using the ViewPager widget, available in Android Support
Library v4. The ViewPager is a layout widget made up of multiple child views where each child view constitutes a
page in the layout:
Typically, ViewPager is used in conjunction with Fragments; however, there are some situations where you might
want to use ViewPager without the added complexity of Fragment s.
ViewPager uses an adapter pattern to provide it with the views to display. The adapter used here is conceptually
similiar to that used by RecyclerView – you supply an implementation of PagerAdapter to generate the pages that
the ViewPager displays to the user. The pages displayed by ViewPager can be View s or Fragment s. When View s
are displayed, the adapter subclasses Android's PagerAdapter base class. If Fragment s are displayed, the adapter
subclasses Android's FragmentPagerAdapter . The Android support library also includes FragmentPagerAdapter (a
subclass of PagerAdapter ) to help with the details of connecting Fragment s to data.
This guide demonstrates both approaches:
In Viewpager with Views, a TreePager app is developed to demonstrate how to use ViewPager to display
views of a tree catalog (an image gallery of deciduous and evergreen trees). PagerTabStrip and
PagerTitleStrip are used to display titles that help with page navigation.
In Viewpager with Fragments, a slightly more complex FlashCardPager app is developed to demonstrate
how to use ViewPager with Fragment s to build an app that presents math problems as flash cards and
responds to user input.
Requirements
To use ViewPager in your app project, you must install the Android Support Library v4 package. For more
information about installing NuGet packages, see Walkthrough: Including a NuGet in your project.
Architecture
Three components are used for implementing gestural navigation with ViewPager :
ViewPager
Adapter
Pager Indicator
Each of these components is summarized below.
ViewPager
ViewPager is a layout manager that displays a collection of View s one at a time. Its job is to detect the user's
swipe gesture and navigate to the next or previous view as appropriate. For example, the screenshot below
demonstrates a ViewPager making the transition from one image to the next in response to a user gesture:
Adapter
ViewPager pulls its data from an adapter. The adapter's job is to create the View s displayed by the ViewPager ,
providing them as needed. The diagram below illustrates this concept – the adapter creates and populates View s
and provides them to the ViewPager . As the ViewPager detects the user's swipe gestures, it asks the adapter to
provide the appropriate View to display:
In this particular example, each View is constructed from a tree image and a tree name before it is passed to the
ViewPager .
Pager Indicator
ViewPager may be used to display a large data set (for example, an image gallery may contain hundreds of
images). To help the user navigate large data sets, ViewPager is often accompanied by a pager indicator that
displays a string. The string might be the image title, a caption, or simply the current view's position within the data
set.
There are two views that can produce this navigation information for you: PagerTabStrip and PagerTitleStrip.
Each displays a string at the top of a ViewPager , and each pulls its data from the ViewPager 's adapter so that it
always stays in sync with the currently-displayed View . The difference between them is that PagerTabStrip
includes a visual indicator for the "current" string while PagerTitleStrip does not (as shown in these screenshots):
This guide demonstrates how to immplement ViewPager , adapter, and indicator app components and integrate
them to support gestural navigation.
Related Links
TreePager (sample)
FlashCardPager (sample)
ViewPager with Views
4/12/2018 • 10 minutes to read • Edit Online
ViewPager is a layout manager that lets you implement gestural navigation. Gestural navigation allows the user
to swipe left and right to step through pages of data. This guide explains how to implement a swipeable UI with
ViewPager and PagerTabStrip, using Views as the data pages (a subsequent guide covers how to use Fragments
for the pages).
Overview
This guide is a walkthrough that provides a step-by-step demonstration how to use ViewPager to implement an
image gallery of deciduous and evergreen trees. In this app, the user swipes left and right through a "tree catalog"
to view tree images. At the top of each page of the catalog, the name of the tree is listed in a PagerTabStrip , and an
image of the tree is displayed in an ImageView . An adapter is used to interface the ViewPager to the underlying
data model. This app implements an adapter derived from PagerAdapter .
Although ViewPager -based apps are often implemented with Fragment s, there are some relatively simple use
cases where the extra complexity of Fragment s is not necessary. For example, the basic image gallery app
illustrated in this walkthrough does not require the use of Fragment s. Because the content is static and the user
only swipes back and forth between different images, the implementation can be kept simpler by using standard
Android views and layouts.
This will also install any additional packages reaquired by Android Support Library v4.
The collection of images in TreeCatalog is organized such that each image can be accessed by an indexer. For
example, the following line of code retrieves the image resource ID for the third image in the collection:
Because the implementation details of TreeCatalog are not relevant to understanding ViewPager , the
TreeCatalog code is not listed here. The source code to TreeCatalog is available at TreeCatalog.cs. Download this
source file (or copy and paste the code into a new TreeCatalog.cs file) and add it to your project. Also, download
and unzip the image files into your Resources/drawable folder and include them in the project.
</android.support.v4.view.ViewPager>
```csharp
This XML defines a `ViewPager` that occupies the entire screen. Note that
you must use the fully-qualified name **android.support.v4.view.ViewPager**
because `ViewPager` is packaged in a support library. `ViewPager` is
available only from
[Android Support Library v4](https://www.nuget.org/packages/Xamarin.Android.Support.v4/);
it is not available in the Android SDK.
## Set up ViewPager
```csharp
using Android.Support.V4.View;
At this point, the ViewPager is empty because it is lacking an adapter for accessing the content in TreeCatalog. In
the next section, a PagerAdapter is created to connect the ViewPager to the TreeCatalog.
Add a new file called TreePagerAdapter.cs and replace its contents with the following code:
using System;
using Android.App;
using Android.Runtime;
using Android.Content;
using Android.Views;
using Android.Widget;
using Android.Support.V4.View;
using Java.Lang;
namespace TreePager
{
class TreePagerAdapter : PagerAdapter
{
public override int Count
{
get { throw new NotImplementedException(); }
}
This code stubs out the essential PagerAdapter implementation. In the following sections, each of these methods is
replaced with working code.
Implement the Constructor
When the app instantiates the TreePagerAdapter , it supplies a context (the MainActivity ) and an instantiated
TreeCatalog . Add the following member variables and constructor to the top of the TreePagerAdapter class in
TreePagerAdapter.cs:
Context context;
TreeCatalog treeCatalog;
The purpose of this constructor is to store the context and TreeCatalog instance that the TreePagerAdapter will
use.
Implement Count
The Count implementation is relatively simple: it returns the number of trees in the tree catalog. Replace Count
with the following code:
public override int Count
{
get { return treeCatalog.NumTrees; }
}
The NumTrees property of TreeCatalog returns the number of trees (number of pages) in the data set.
Implement InstantiateItem
The InstantiateItem method creates the page for a given position. It must also add the newly-created view to the
ViewPager 's view collection. To make this possible, the ViewPager passes itself as the container parameter.
When the ViewPager displays the image at position , it displays this ImageView . Initially, InstantiateItem is called
twice to populate the first two pages with views. As the user scrolls, it is called again to maintain views just behind
and ahead of the currently displayed item.
Implement DestroyItem
The DestroyItem method removes a page from the given position. In apps where the view at any given position
can change, ViewPager must have some way of removing a stale view at that position before replacing it with a
new view. In the TreeCatalog example, the view at each position does not change, so a view removed by
DestroyItem will simply be re-added when InstantiateItem is called for that position. ( For better efficiency, one
could implement a pool to recycle View s that will be re-displayed at the same position.)
Replace the DestroyItem method with the following code:
This code instantiates the TreePagerAdapter , passing in the MainActivity as the context ( this ). The instantiated
TreeCatalog is passed into the constructor's second argument. The ViewPager 's Adapter property is set to the
instantiated TreePagerAdapter object; this plugs the TreePagerAdapter into the ViewPager .
The core implementation is now complete – build and run the app. You should see the first image of the tree
catalog appear on the screen as shown on the left in the next screenshot. Swipe left to see more tree views, then
swipe right to move back through the tree catalog:
Add a Pager Indicator
This minimal ViewPager implementation displays the images of the tree catalog, but it provides no indication as to
where the user is within the catalog. The next step is to add a PagerTabStrip . The PagerTabStrip informs the user
as to which page is displayed and provides navigation context by displaying a hint of the previous and next pages.
PagerTabStrip is intended to be used as an indicator for the current page of a ViewPager ; it scrolls and updates as
the user swipes through each page.
Open Resources/layout/Main.axml and add a PagerTabStrip to the layout:
<android.support.v4.view.PagerTabStrip
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:paddingBottom="10dp"
android:paddingTop="10dp"
android:textColor="#fff" />
</android.support.v4.view.ViewPager>
ViewPager and PagerTabStrip are designed to work together. When you declare a PagerTabStrip inside a
ViewPager layout, the ViewPager will automatically find the PagerTabStrip and connect it to the adapter. When
you build and run the app, you should see the empty PagerTabStrip displayed at the top of each screen:
Display a Title
To add a title to each page tab, implement the GetPageTitleFormatted method in the PagerAdapter -derived class.
ViewPager calls GetPageTitleFormatted (if implemented) to obtain the title string that describes the page at the
specified position. Add the following method to the TreePagerAdapter class in TreePagerAdapter.cs:
This code retrieves the tree caption string from the specified page (position) in the tree catalog, converts it into a
Java String , and returns it to the ViewPager . When you run the app with this new method, each page displays the
tree caption in the PagerTabStrip . You should see the tree name at the top of the screen without an underline:
You can swipe back and forth to view each captioned tree image in the catalog.
PagerTitleStrip Variation
PagerTitleStrip is very similar to PagerTabStrip except that PagerTabStrip adds an underline for the currently
selected tab. You can replace PagerTabStrip with PagerTitleStrip in the above layout and run the app again to
see how it looks with PagerTitleStrip :
Summary
This walkthrough provided a step-by-step example of how to build a basic ViewPager -based app without using
Fragment s. It presented an example data source containing images and caption strings, a ViewPager layout to
display the images, and a PagerAdapter subclass that connects the ViewPager to the data source. To help the user
navigate through the data set, instructions were included that explain how to add a PagerTabStrip or
PagerTitleStrip to display the image caption at the top of each page.
Related Links
TreePager (sample)
ViewPager with Fragments
4/12/2018 • 12 minutes to read • Edit Online
ViewPager is a layout manager that lets you implement gestural navigation. Gestural navigation allows the user
to swipe left and right to step through pages of data. This guide explains how to implement a swipeable UI with
ViewPager, using Fragments as the data pages.
Overview
ViewPager is often used in conjunction with fragments so that it is easier to manage the lifecycle of each page in
the ViewPager . In this walkthrough, ViewPager is used to create an an app called FlashCardPager that presents a
series of math problems on flash cards. Each flash card is implemented as a fragment. The user swipes left and
right through the flash cards and taps on a math problem to reveal its answer. This app creates a Fragment
instance for each flash card and implements an adapter derived from FragmentPagerAdapter . In Viewpager and
Views, most of the work was done in MainActivity lifecycle methods. In FlashCardPager, most of the work will
be done by a Fragment in one of its lifecycle methods.
This guide does not cover the basics of fragments – if you are not yet familiar with fragments in Xamarin.Android,
see Fragments to help you get started with fragments.
The collection of flash cards in FlashCardDeck is organized such that each flash card can be accessed by an indexer.
For example, the following line of code retrieves the fourth flash card problem in the deck:
This line of code retrieves the corresponding answer to the previous problem:
Because the implementation details of FlashCardDeck are not relevant to understanding ViewPager , the
FlashCardDeck code is not listed here. The source code to FlashCardDeck is available at FlashCardDeck.cs.
Download this source file (or copy and paste the code into a new FlashCardDeck.cs file) and add it to your
project.
Create a ViewPager Layout
Open Resources/layout/Main.axml and replace its contents with the following XML:
</android.support.v4.view.ViewPager>
This XML defines a ViewPager that occupies the entire screen. Note that you must use the fully-qualified name
android.support.v4.view.ViewPager because ViewPager is packaged in a support library. ViewPager is available
only from the Android Support Library v4; it is not available in the Android SDK.
Set up ViewPager
Edit MainActivity.cs and add the following using statements:
using Android.Support.V4.View;
using Android.Support.V4.App;
MainActivity is derived from FragmentActivity (rather than Activity ) because FragmentActivity knows how to
manage the support of fragments. Replace the OnCreate method with the following code:
This layout defines a single flash card fragment; each fragment is comprised of a TextView that displays a math
problem using a large (100sp) font. This text is centered vertically and horizontally on the flash card.
Create the Initial FlashCardFragment Class
Add a new file called FlashCardFragment.cs and replace its contents with the following code:
using System;
using Android.OS;
using Android.Views;
using Android.Widget;
using Android.Support.V4.App;
namespace FlashCardPager
{
public class FlashCardFragment : Android.Support.V4.App.Fragment
{
public FlashCardFragment() { }
This code stubs out the essential Fragment definition that will be used to display a flash card. Note that
FlashCardFragment is derived from the support library version of Fragment defined in
Android.Support.V4.App.Fragment . The constructor is empty so that the newInstance factory method is used to
create a new FlashCardFragment instead of a constructor.
The OnCreateViewlifecycle method creates and configures the TextView . It inflates the layout for the fragment's
TextView and returns the inflated TextView to the caller. LayoutInflater and ViewGroup are passed to
OnCreateView so that it can inflate the layout. The savedInstanceState bundle contains data that OnCreateView
uses to recreate the TextView from a saved state.
The fragment's view is explicitly inflated by the call to inflater.Inflate . The container argument is the view's
parent, and the false flag instructs the inflater to refrain from adding the inflated view to the view's parent (it will
be added when ViewPager call's the adapter's GetItem method later in this walkthrough).
Modify the newInstance factory method so that it creates a Bundle object and uses the above keys to store the
passed question and answer text in the fragment after it is instantiated:
return fragment;
}
Modify the fragment lifecycle method OnCreateView to retrieve this information from the passed-in Bundle and
load the question text into the TextBox :
return view;
}
The answer variable is not used here, but it will be used later when event handler code is added to this file.
using System;
using Android.Views;
using Android.Widget;
using Android.Support.V4.App;
namespace FlashCardPager
{
class FlashCardDeckAdapter : FragmentPagerAdapter
{
public FlashCardDeckAdapter (Android.Support.V4.App.FragmentManager fm, FlashCardDeck flashCards)
: base(fm)
{
}
This code stubs out the essential FragmentPagerAdapter implementation. In the following sections, each of these
methods is replaced with working code. The purpose of the constructor is to pass the fragment manager to the
FlashCardDeckAdapter 's base class constructor.
this.flashCardDeck = flashCards;
This line of code stores the FlashCardDeck instance that the FlashCardDeckAdapter will use.
Implement Count
The Count implementation is relatively simple: it returns the number of flash cards in the flash card deck. Replace
Count with the following code:
The NumCards property of FlashCardDeck returns the number of flash cards (number of fragments) in the data set.
Implement GetItem
The GetItem method returns the fragment associated with the given position. When GetItem is called for a
position in the flash card deck, it returns a FlashCardFragment configured to display the flash card problem at that
position. Replace the GetItem method with the following code:
FlashCardDeckAdapter adapter =
new FlashCardDeckAdapter(SupportFragmentManager, flashCards);
viewPager.Adapter = adapter;
This code instantiates the FlashCardDeckAdapter , passing in the SupportFragmentManager in the first argument. (The
SupportFragmentManager property of FragmentActivity is used to get a reference to the FragmentManager – for more
information about the FragmentManager , see Managing Fragments.)
The core implementation is now complete – build and run the app. You should see the first image of the flash card
deck appear on the screen as shown on the left in the next screenshot. Swipe left to see more flash cards, then
swipe right to move back through the flash card deck:
Add a Pager Indicator
This minimal ViewPager implementation displays each flash card in the deck, but it provides no indication as to
where the user is within the deck. The next step is to add a PagerTabStrip . The PagerTabStrip informs the user as
to which problem number is displayed and provides navigation context by displaying a hint of the previous and
next flash cards.
Open Resources/layout/Main.axml and add a PagerTabStrip to the layout:
<android.support.v4.view.PagerTabStrip
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:paddingBottom="10dp"
android:paddingTop="10dp"
android:textColor="#fff" />
</android.support.v4.view.ViewPager>
When you build and run the app, you should see the empty PagerTabStrip displayed at the top of each flash card:
Display a Title
To add a title to each page tab, implement the GetPageTitleFormatted method in the adapter. ViewPager calls
GetPageTitleFormatted (if implemented) to obtain the title string that describes the page at the specified position.
Add the following method to the FlashCardDeckAdapter class in FlashCardDeckAdapter.cs:
This code converts the position in the flash card deck to a problem number. The resulting string is converted into a
Java String that is returned to the ViewPager . When you run the app with this new method, each page displays
the problem number in the PagerTabStrip :
You can swipe back and forth to see the problem number in the flash card deck that is displayed at the top of each
flash card.
questionBox.Click += delegate
{
Toast.MakeText(Activity.ApplicationContext,
"Answer: " + answer, ToastLength.Short).Show();
};
This Click event handler displays the answer in a Toast that appears when the user taps the TextBox . The answer
variable was initialized earlier when state information was read from the Bundle that was passed to OnCreateView .
Build and run the app, then tap the problem text on each flash card to see the answer:
The FlashCardPager presented in this walkthrough uses a MainActivity derived from FragmentActivity , but you
can also derive MainActivity from AppCompatActivity (which also provides support for managing fragments). To
view an AppCompatActivity example, see FlashCardPager in the Sample Gallery.
Summary
This walkthrough provided a step-by-step example of how to build a basic ViewPager -based app using Fragment s.
It presented an example data source containing flash card questions and answers, a ViewPager layout to display
the flash cards, and a FragmentPagerAdapter subclass that connects the ViewPager to the data source. To help the
user navigate through the flash cards, instructions were included that explain how to add a PagerTabStrip to
display the problem number at the top of each page. Finally, event handling code was added to display the answer
when the user taps on a flash card problem.
Related Links
FlashCardPager (sample)
Web View
7/25/2018 • 2 minutes to read • Edit Online
WebView allows you to create your own window for viewing web pages (or even develop a complete browser). In
this tutorial, you'll create a simple Activity that can view and navigate web pages.
Create a new project named HelloWebView.
Open Resources/Layout/Main.axml and insert the following:
Because this application will access the Internet, you must add the appropriate permissions to the Android
manifest file. Open your project's properties to specify which permissions your application requires to operate.
Enable the INTERNET permission as shown below:
using Android.Webkit;
WebView web_view;
When the WebView is asked to load a URL, it will by default delegate the request to the default browser. To have
the WebView load the URL (rather than the default browser), you must subclass Android.Webkit.WebViewClient
and override the ShouldOverriderUrlLoading method. An instance of this custom WebViewClient is provided to the
WebView . To do this, add the following nested HelloWebViewClient class inside MainActivity :
When ShouldOverrideUrlLoading returns false , it signals to Android that the current WebView instance handled
the request and that no further action is necessary.
If you are targeting API level 24 or later, use the overload of ShouldOverrideUrlLoading that takes an
IWebResourceRequest for the second argument instead of a string :
This initializes the member WebView with the one from the Activity layout and enables JavaScript for the
WebView with JavaScriptEnabled = true (see the Call C# from JavaScript recipe for information about how to call
C# functions from JavaScript). Finally, an initial web page is loaded with LoadUrl(String) .
Build and run the app. You should see a simple web page viewer app as the one seen in the following screenshot:
To handle the BACK button key press, add the following using statement:
using Android.Views;
This OnKeyDown(int, KeyEvent) callback method will be called whenever a button is pressed while the Activity is
running. The condition inside uses the KeyEvent to check whether the key pressed is the BACK button and
whether the WebView is actually capable of navigating back (if it has a history). If both are true, then the GoBack()
method is called, which will navigate back one step in the WebView history. Returning true indicates that the event
has been handled. If this condition is not met, then the event is sent back to the system.
Run the application again. You should now be able to follow links and navigate back through the page history:
Portions of this page are modifications based on work created and shared by the Android Open Source Project
and used according to terms described in the Creative Commons 2.5 Attribution License.
Related Links
Call C# from JavaScript
Android.Webkit.WebView
KeyEvent
Platform Features
7/23/2018 • 3 minutes to read • Edit Online
Documents in this section cover features specific to Android. Here you'll find topics such as using Fragments,
working with maps and encapsulating data with Content Providers.
Android Beam
Android Beam is a new Near Field Communication (NFC ) technology in Android 4 that allows applications to
share information over NFC when in close proximity.
Fingerprint Authentication
This section discusses how to use fingerprint authentication, first introduced in Android 6.0, to a Xamarin.Android
application.
Fragments
Android 3.0 introduced Fragments, showing how to support more flexible designs for the many different screen
sizes found on phones and tablets. This article will cover how to use Fragments to develop Xamarin.Android
applications, and also how to support Fragments on pre-Android 3.0 (API Level 11) devices.
App-Linking
This guide will discuss how Android 6.0 supports app -linking, a technique that allows mobile apps to respond to
URLs on websites. It will discuss how to implement app-linking in an Android 6.0 application and how to configure
a website to grant permissions to the mobile app to handle app-links for the domain.
Android 8 Oreo
This article provides an outline of the new features in Android Oreo, explains how to prepare Xamarin.Android for
Android Oreo development, and provides links to sample applications that illustrate how to use Android Oreo
features in Xamarin.Android apps.
Android 7 Nougat
This article provides a high level overview of the new features introduced in Android 7.0 Nougat.
Android 6 Marshmallow
This article provides a high level overview of the new features introduced in Android 6.0 Marshmallow.
Android 5 Lollipop
This guide provides an overview of new Android 5.0 Lollipop features such as Material Theme, CardView,
RecyclerView, and Heads Up Notifications, and it links to in-depth articles that help you use these new features in
your app.
Android Speech
This section discusses how to use the Android Text to Speech and Speech to Text facilities. It also covers installing
language packs and interpretation of the text spoken to the device.
Renderscript
This guide discusses Renderscript.
Android Beam
4/12/2018 • 2 minutes to read • Edit Online
Android Beam is a Near Field Communication (NFC ) technology introduced in Android 4.0 that allows
applications to share information over NFC when in close proximity.
Android Beam works by pushing messages over NFC when two devices are in range. Devices about 4cm from
each other can share data using Android Beam. An Activity on one device creates a message and specifies an
Activity (or Activities) that can handle pushing it. When the specified Activity is in the foreground and the devices
are in range, Android Beam will push the message to the second device. On the receiving device, an Intent is
invoked containing the message data.
Android supports two ways of setting messages with Android Beam:
SetNdefPushMessage- Before Android Beam is initiated, an application can call SetNdefPushMessage to
specify an NdefMessage to push over NFC, and the Activity that is pushing it. This mechanism is best used
when a message doesn’t change while an application is in use.
SetNdefPushMessageCallback - When Android Beam is initiated, an application can handle a callback to
create an NdefMessage. This mechanism allows for message creation to be delayed until devices are in
range. It supports scenarios where the message may vary based upon what’s happening in the application.
In either case, to send data with Android Beam, an application sends an NdefMessage , packaging the data in several
NdefRecords . Let’s take a look at the key points that must be addressed before we can trigger Android Beam. First,
we’ll work with the callback style of creating an NdefMessage .
Creating a Message
We can register callbacks with an NfcAdapter in the Activity’s OnCreate method. For example, assuming an
NfcAdapter named mNfcAdapter is declared as a class variable in the Activity, we can write the following code to
create the callback that will construct the message:
Receiving a Message
On the receiving side, the system invokes an Intent with the ActionNdefDiscovered action, from which we can
extract the NdefMessage as follows:
For a complete code example that uses Android Beam, shown running in the screenshot below, see the Android
Beam demo in the Sample Gallery.
Related Links
Android Beam Demo (sample)
Introducing Ice Cream Sandwich
Android 4.0 Platform
Working with the Android Manifest
7/25/2018 • 6 minutes to read • Edit Online
Overview
AndroidManifest.xml is a powerful file in the Android platform that allows you to describe the functionality and
requirements of your application to Android. However, working with it is not easy. Xamarin.Android helps to
minimize this difficulty by allowing you to add custom attributes to your classes, which will then be used to
automatically generate the manifest for you. Our goal is that 99% of our users should never need to manually
modify AndroidManifest.xml.
AndroidManifest.xml is generated as part of the build process, and the XML found within
Properties/AndroidManifest.xml is merged with XML that is generated from custom attributes. The resulting
merged AndroidManifest.xml resides in the obj subdirectory; for example, it resides at
obj/Debug/android/AndroidManifest.xml for Debug builds. The merging process is trivial: it uses custom
attributes within the code to generate XML elements, and inserts those elements into AndroidManifest.xml.
The Basics
At compile time, assemblies are scanned for non- abstract classes that derive from Activity and have the
[Activity] attribute declared on them. It then uses these classes and attributes to build the manifest. For
example, consider the following code:
namespace Demo
{
public class MyActivity : Activity
{
}
}
This results in nothing being generated in AndroidManifest.xml. If you want an <activity/> element to be
generated, you need to use the [Activity] custom attribute:
namespace Demo
{
[Activity]
public class MyActivity : Activity
{
}
}
The [Activity] attribute has no effect on abstract types; abstract types are ignored.
Activity Name
Beginning with Xamarin.Android 5.1, the type name of an activity is based on the MD5SUM of the assembly-
qualified name of the type being exported. This allows the same fully-qualified name to be provided from two
different assemblies and not get a packaging error. (Before Xamarin.Android 5.1, the default type name of the
activity was created from the lowercased namespace and the class name.)
If you wish to override this default and explicitly specify the name of your activity, use the Name property:
[Activity (Name="awesome.demo.activity")]
public class MyActivity : Activity
{
}
Note: you should use the Name property only for backward-compatibility reasons, as such renaming can slow
down type lookup at runtime. If you have legacy code that expects the default type name of the activity to be
based on the lowercased namespace and the class name, see Android Callable Wrapper Naming for tips on
maintaining compatibility.
Activity Title Bar
By default, Android gives your application a title bar when it is run. The value used for this is
/manifest/application/activity/@android:label . In most cases, this value will differ from your class name. To
specify your app's label on the title bar, use the Label property. For example:
Activity Icon
By default, your activity will be given the default launcher icon provided by the system. To use a custom icon, first
add your .png to Resources/drawable, set its Build Action to AndroidResource, then use the Icon property to
specify the icon to use. For example:
Permissions
When you add permissions to the Android Manifest (as described in Add Permissions to Android Manifest), these
permissions are recorded in Properties/AndroidManifest.xml. For example, if you set the INTERNET
permission, the following element is added to Properties/AndroidManifest.xml:
Debug builds automatically set some permissions to make debug easier (such as INTERNET and
READ_EXTERNAL_STORAGE ) – these settings are set only in the generated
obj/Debug/android/AndroidManifest.xml and are not shown as enabled in the Required permissions
settings.
For example, if you examine the generated manifest file at obj/Debug/android/AndroidManifest.xml, you
may see the following added permission elements:
In the Release build version of the manifest (at obj/Debug/android/AndroidManifest.xml), these permissions
are not automatically configured. If you find that switching to a Release build causes your app to lose a
permission that was available in the Debug build, verify that you have explicitly set this permission in the
Required permissions settings for your app (see Build > Android Application in Visual Studio for Mac; see
Properties > Android Manifest in Visual Studio).
Advanced Features
Intent Actions and Features
The Android manifest provides a way for you to describe the capabilities of your activity. This is done via Intents
and the [IntentFilter] custom attribute. You can specify which actions are appropriate for your activity with the
IntentFilter constructor, and which categories are appropriate with the Categories property. At least one
activity must be provided (which is why activities are provided in the constructor). [IntentFilter] can be
provided multiple times, and each use results in a separate <intent-filter/> element within the <activity/> .
For example:
[Activity (Label="Awesome Demo App", MainLauncher=true, Icon="@drawable/myicon")]
[IntentFilter (new[]{Intent.ActionView},
Categories=new[]{Intent.CategorySampleCode, "my.custom.category"})]
public class MyActivity : Activity
{
}
Application Element
The Android manifest also provides a way for you to declare properties for your entire application. This is done
via the <application> element and its counterpart, the Application custom attribute. Note that these are
application-wide (assembly-wide) settings rather than per-Activity settings. Typically, you declare <application>
properties for your entire application and then override these settings (as needed) on a per-Activity basis.
For example, the following Application attribute is added to AssemblyInfo.cs to indicate that the application
can be debugged, that its user-readable name is My App, and that it uses the Theme.Light style as the default
theme for all activities:
In this example, all activities in the app will default to the Theme.Light style. If you set an Activity's theme to
Theme.Dialog , only that Activity will use the Theme.Dialog style while all other activities in your app will default to
the Theme.Light style as set in the <application> element.
The Application element is not the only way to configure <application> attributes. Alternately, you can insert
attributes directly into the <application> element of Properties/AndroidManifest.xml. These settings are
merged into the final <application> element that resides in obj/Debug/android/AndroidManifest.xml. Note
that the contents of Properties/AndroidManifest.xml always override data provided by custom attributes.
There are many application-wide attributes that you can configure in the <application> element; for more
information about these settings, see the Public Properties section of ApplicationAttribute.
List of Custom Attributes
Android.App.ActivityAttribute : Generates a /manifest/application/activity XML fragment
Android.App.ApplicationAttribute : Generates a /manifest/application XML fragment
Android.App.InstrumentationAttribute : Generates a /manifest/instrumentation XML fragment
Android.App.IntentFilterAttribute : Generates a //intent-filter XML fragment
Android.App.MetaDataAttribute : Generates a //meta-data XML fragment
Android.App.PermissionAttribute : Generates a //permission XML fragment
Android.App.PermissionGroupAttribute : Generates a //permission-group XML fragment
Android.App.PermissionTreeAttribute : Generates a //permission-tree XML fragment
Android.App.ServiceAttribute : Generates a /manifest/application/service XML fragment
Android.App.UsesLibraryAttribute : Generates a /manifest/application/uses-library XML fragment
Android.App.UsesPermissionAttribute : Generates a /manifest/uses-permission XML fragment
Android.Content.BroadcastReceiverAttribute : Generates a /manifest/application/receiver XML fragment
Android.Content.ContentProviderAttribute : Generates a /manifest/application/provider XML fragment
Android.Content.GrantUriPermissionAttribute : Generates a /manifest/application/provider/grant-uri-
permission XML fragment
File Storage and Access with Xamarin.Android
7/23/2018 • 7 minutes to read • Edit Online
A common requirement for Android apps is to manipulate files – saving pictures, downloading documents, or
exporting data to share with other programs. Android (which is based on Linux) supports this by providing space
for file storage. Android groups the filesystem into two different types of storage:
Internal Storage – this is a portion of the file system that can be accessed only by the application or the
operating system.
External Storage – this is a partition for the storage of files that is accessible by all apps, the user, and possibly
other devices. On some devices, external storage may be removable (such as an SD card).
These groupings are conceptual only, and don't necessarily refer to a single partition or directory on the device. An
Android device will always provide partition for internal storage and external storage. It is possible that certain
devices may have multiple partitions that are considered to be external storage. Regardless of the partition the
APIs for reading, writing, or creating files is the same. There are two sets of APIs that a Xamarin.Android
application may use for file access:
1. The .NET APIs (provided by Mono and wrapped by Xamarin.Android) – These includes the file system
helpers provided by Xamarin.Essentials. The .NET APIs provide the best cross-platform compatibility and as
such the focus of this guide will be on these APIs.
2. The native Java file access APIs (provided by Java and wrapped by Xamarin.Android) – Java provides
its own APIs for reading and writing files. These are a completely acceptable alternative to to the .NET APIs, but
are specific to Android and are not suitable for apps that are intended to be cross-platform.
Reading and writing to files is almost identical in Xamarin.Android as it is to any other .NET application. The
Xamarin.Android app determines the path to the file that will be manipulated, then uses standard .NET idioms for
file access. Because the actual paths to internal and external storage may vary from device to device or from
Android version to Android version, it is not recommended to hard code the path to the files. Instead, use the
Xamarin.Android APIs to determine the path to files. That way, the .NET APIs for reading and writing files exposes
the native Android APIs that will help with determining the path to files on internal and external storage.
Before discussing the APIs involved with file access, it is important to understand some of the details surrounding
internal and external storage. This will be discussed in the next section.
NOTE
For devices that support multiple users, Android will provide each user their own directory on both internal and external
storage. This directory is inaccessible to other users on the device. This separation is invisible to apps as long as they do not
hardcode paths to files on internal or external storage.
As a rule of thumb, Xamarin.Android apps should prefer saving their files on internal storage when it is reasonable,
and rely on external storage when files need to be shared with other apps, are very large, or should be retained
even if the app is uninstalled. For example, a configuration file is best suited for a internal storage as it has no
importance except to the app that creates it. In contrast, photos are a good candidate for external storage. They can
be very large and in many cases the user may want to share them or access them even if the app is uninstalled.
This guide will focus on internal storage. Please see the guide External storage for details on using external storage
in a Xamarin.Android application.
/data/user/0/com.companyname/files
IMPORTANT
The exact path to the internal storage directory can vary from device to device and between versions of Android. Because of
this, apps must not hard code the path to the internal files storage directory, and instead use the Xamarin.Android APIs, such
as System.Environment.GetFolderPath() .
To maximize code sharing, Xamarin.Android apps (or Xamarin.Forms apps targeting Xamarin.Android) should use
the System.Environment.GetFolderPath() method. In Xamarin.Android, this method will return a string for a
directory that is the same location as Android.Content.Context.FilesDir . This method takes an enum,
System.Environment.SpecialFolder , which is used to identify a set of enumerated constants that represent the paths
of special folders used by the operating system. Not all of the System.Environment.SpecialFolder values will map to
a valid directory on Xamarin.Android. The following table describes what path can be expected for a given value of
System.Environment.SpecialFolder :
SYSTEM.ENVIRONMENT.SPECIALFOLDER PATH
ApplicationData INTERNAL_STORAGE/.config
SYSTEM.ENVIRONMENT.SPECIALFOLDER PATH
Desktop INTERNAL_STORAGE/Desktop
LocalApplicationData INTERNAL_STORAGE/.local/share
MyComputer INTERNAL_STORAGE/.local/share
MyDocuments INTERNAL_STORAGE
MyMusic INTERNAL_STORAGE/Music
MyPictures INTERNAL_STORAGE/Music
MyVideos INTERNAL_STORAGE/Videos
Personal INTERNAL_STORAGE
The next code snippet provides one way to read an integer value that was stored in a text file:
public async Task<int> ReadCountAsync()
{
var backingFile =
Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "count.txt");
var count = 0;
using (var reader = new StreamReader(backingFile, true))
{
string line;
while ((line = await reader.ReadLineAsync()) != null)
{
if (int.TryParse(line, out var newcount))
{
count = newcount;
}
}
}
return count;
}
Related Links
External Storage
Save files on device storage
Xamarin.Essentials File System Helpers
Backup user data with Auto Backup
Adoptable Storage
External storage
7/23/2018 • 9 minutes to read • Edit Online
External storage refers to file storage that is not on internal storage and not exclusively accessible to the app that is
responsible for the file. The primary purpose of external storage is to provide a place to put files that are meant to
be shared between apps or that are too large to fit on the internal storage.
Historically speaking, external storage referred to a disk partition on removable media such as an SD card (was
also known as portable storage). This distinction is no longer as relevant as Android devices have evolved and
many Android devices no longer support removable storage. Instead some devices will allocate some of their
internal non-volatile memory which Android to perform the same function removable media. This is known as
emulated storage and is still considered to be external storage. Alternately, some Android devices may have
multiple external storage partitions. For example, an Android tablet (in addition to its internal storage) might have
emulated storage and one or more slots for an SD card. All of these partitions are treated by Android as external
storage.
On devices that have multiple users, each user will have a dedicated directory on the primary external storage
partition for their external storage. Apps running as one user will not have access to files from another user on the
device. The files for all users are still world-readable and world-writeable; however, Android will sandbox each user
profile fromthe others.
Reading and writing to files is almost identical in Xamarin.Android as it is to any other .NET application. The
Xamarin.Android app determines the path to the file that will be manipulated, then uses standard .NET idioms for
file access. Because the actual paths to internal and external storage may vary from device to device or from
Android version to Android version, it is not recommended to hard code the path to the files. Instead,
Xamarin.Android exposes the native Android APIs that will help with determining the path to files on internal and
external storage.
This guide will discuss the concepts and APIs in Android that are specific to external storage.
/storage/emulated/0/Android/data/com.companyname.app/files/
This document will refer to the storage directory for private files on external storage as
PRIVATE_EXTERNAL_STORAGE.
The parameter for GetExternalFilesDir() is a string that specifies an application directory. This is a directory
intended to provide a standard location for a logical organization of files. The string values are available through
constants on the Android.OS.Environment class:
ANDROID.OS.ENVIRONMENT DIRECTORY
DirectoryAlarms PRIVATE_EXTERNAL_STORAGE/Alarms
DirectoryDcim PRIVATE_EXTERNAL_STORAGE/DCIM
DirectoryDownloads PRIVATE_EXTERNAL_STORAGE/Download
DirectoryDocuments PRIVATE_EXTERNAL_STORAGE/Documents
DirectoryMovies PRIVATE_EXTERNAL_STORAGE/Movies
DirectoryMusic PRIVATE_EXTERNAL_STORAGE/Music
DirectoryNotifications PRIVATE_EXTERNAL_STORAGE/Notifications
DirectoryPodcasts PRIVATE_EXTERNAL_STORAGE/Podcasts
DirectoryRingtones PRIVATE_EXTERNAL_STORAGE/Ringtones
DirectoryPictures PRIVATE_EXTERNAL_STORAGE/Pictures
For devices that have multiple external storage partitions, each partition will have a directory that is intended for
private files. The method Android.Content.Context.GetExternalFilesDirs(string type) will return an array of
Java.IO.Files . Each object will represent a private application-specific directory on all shared/external storage
devices where the application can place the files it owns.
IMPORTANT
The exact path to the private exteral storage directory can vary from device to device and between versions of Android.
Because of this, apps must not hard code the path to this directory, and instead use the Xamarin.Android APIs, such as
Android.Content.Context.GetExternalFilesDir() .
/storage/emulated/0/
This document will refer to the storage directory for public files on external storage as
PUBLIC_EXTERNAL_STORAGE.
Android also supports the concept of application directories on PUBLIC_EXTERNAL_STORAGE. These directories
are exactly the same as the application diretories for _PRIVATE\_EXTERNAL\_STORAGE_ and are described in the table
in the previous section. The method
Android.OS.Environment.GetExternalStoragePublicDirectory(string directoryType) will return a Java.IO.File object
that correspond to a public application directory. The directoryType parameter is a mandatory parameter and
cannot be null .
For example, calling Environment.GetExternalStoragePublicDirectory(Environment.DirectoryDocuments).AbsolutePath
will return a string which will resemble:
/storage/emulated/0/Documents
IMPORTANT
The exact path to the public external storage directory can vary from device to device and between versions of Android.
Because of this, apps must not hard code the path to this directory, and instead use the Xamarin.Android APIs, such as
Android.OS.Environment.ExternalStorageDirectory .
MediaNofs Media is present but does not contain a filesystem suitable for
Android.
Most Android apps will only need to check if external storage is mounted. The following code snippet shows how
to verify that external storage is mounted for read-only access or read-write access:
NOTE
If the user grants WRITE_EXTERNAL_STORAGE , then READ_EXTERNAL_STORAGE is also implicitly granted. It is not necessary to
request both permissions in AndroidManifest.xml.
Visual Studio
Visual Studio for Mac
The permissions may also be added using the Android Manifest tab of the solution properties:
Generally speaking, all dangerous permissions must be approved by the user. The permissions for external storage
are an anomaly in that there are exceptions to this rule, depending on the version of Android that the app is
running:
For more information on performing runtime permission requests, please consult the guide Permissions In
Xamarin.Android. The monodroid-sample LocalFiles also demonstrates one way of performing runtime
permission checks.
Granting and revoking permissions with ADB
In the course of developing an Android app, it may be necessary to grant and revoke permissions to test the
various work flows involved with runtime permission checks. It is possible to do this at the command prompt
using ADB. The following command line snippets demonstrate how to grant or revoke permissions using ADB for
an Android app whose package name is com.companyname.app:
Deleting files
Any of the standard C# APIs can be used to delete a file from external storage, such as System.IO.File.Delete . It is
also possible to use the Java APIs at the expense of code portability. For example:
System.IO.File.Delete("/storage/emulated/0/Android/data/com.companyname.app/files/count.txt");
Related Links
Xamarin.Android Local Files sample on monodroid-samples
Permissions In Xamarin.Android
Fingerprint Authentication
4/12/2018 • 2 minutes to read • Edit Online
This guide discusses how to add fingerprint authentication, introduced in Android 6.0, to a Xamarin.Android
application.
The FingerprintManager.Authenticate method is used by an Android application to start the fingerprint scanner.
The following snippet is an example of how to invoke it using the Support Library compatibility APIs:
This guide will discuss how to use the FingerprintManager APIs to enhance an Android application with fingerprint
authentication. It will cover how to instantiate and create a CryptoObject to help secure the results from the
fingerprint scanner. We'll examine how an application should subclass FingerprintManager.AuthenticationCallback
and respond to feedback from the fingerprint scanner. Finally, we'll see how to enroll a fingerprint on an Android
device or emulator and how to use adb to simulate a fingerprint scan.
Requirements
Fingerprint Authentication requires Android 6.0 (API level 23) or higher and a device with a fingerprint scanner.
A fingerprint must already be enrolled with the device for each user that is to be authenticated. This involves
setting up a screen lock that uses a password, PIN, swipe pattern, or facial recognition. It is possible to simulate
some of the fingerprint authentication functionality in an Android Emulator. For more information on these two
topics, please see the Enrolling a Fingerprint section.
Related Links
Fingerprint Guide Sample App
Fingerprint Dialog Sample
Requesting Permissions at Runtime
android.hardware.fingerprint
android.support.v4.hardware.fingerprint
Android.Content.Context
Fingerprint and payments API (video)
Getting Started with Fingerprint Authentication
4/12/2018 • 3 minutes to read • Edit Online
To get started, let's first cover how to configure a Xamarin.Android project so that the application is able to use
fingerprint authentication:
1. Update AndroidManifest.xml to declare the permissions that the Fingerprint APIs require.
2. Obtain a reference to the FingerprintManager .
3. Check that the device is capable of fingerprint scanning.
In the previous snippet, the context is any Android Android.Content.Context . Typically this is the Activity which is
performing the authentication.
Hardware – When the application starts up for the first time, it should check for the presence of a fingerprint
scanner:
Device Is Secured – The user must have the device secured with a screen lock. If the user has not secured the
device with a screen lock and security is important to the application, then the user should be notified that a screen
lock must be configured. The following code snippet shows how to check this pre-requiste:
Enrolled Fingerprints – The user must have at least one fingerprint registered with the operating system. This
permission check should occur prior to each authentication attempt:
Permissions – The application must request permission from the user before using the application. For Android
5.0 and lower, the user grants the permission as a condition of installing the app. Android 6.0 introduced a new
permission model that checks permissions at run-time. This code snippet is an example of how to check for
permissions on Android 6.0:
// The context is typically a reference to the current activity.
Android.Content.PM.Permission permissionResult = ContextCompat.CheckSelfPermission(context,
Manifest.Permission.UseFingerprint);
if (permissionResult == Android.Content.PM.Permission.Granted)
{
// Permission granted - go ahead and start the fingerprint scanner.
}
else
{
// No permission. Go and ask for permissions and don't start the scanner. See
// http://developer.android.com/training/permissions/requesting.html
}
An application should check conditions 3, 4, and 5 each time it wishes to use fingerprint authentication. The first
two conditions can be checked the first time an application is run on a device and the results saved (in shared
preferences for example).
For more information on how to request permissions in Android 6.0, consult the Android guide Requesting
Permissions at Run-Time.
Related Links
Context
ContextCompat
KeyguardManager
FingerprintManager
FingerprintManagerCompat
Requesting Permissions at Run-Time
Scanning For Fingerprints
4/12/2018 • 3 minutes to read • Edit Online
Now that we have seen how to prepare a Xamarin.Android application to use fingerprint authentication, let's return
to the FingerprintManager.Authenticate method, and discuss its place in the Android 6.0 fingerprint authentication.
A quick overview of the workflow for fingerprint authentication is described in this list:
1. Invoke FingerprintManager.Authenticate , passing a CryptoObject and a
FingerprintManager.AuthenticationCallback instance. The CryptoObject is used to ensure that the fingerprint
authentication result was not tampered with.
2. Subclass the FingerprintManager.AuthenticationCallback class. An instance of this class will be provided to
FingerprintManager when fingerprint authentication starts. When the fingerprint scanner is finished, it will
invoke one of the callback methods on this class.
3. Write code to update the UI to let the user know that the device has started the fingerprint scanner and is
waiting for user interaction.
4. When the fingerprint scanner is done, Android will return results to the application by invoking a method on the
FingerprintManager.AuthenticationCallback instance that was provided in the previous step.
5. The application will inform the user of the fingerprint authentication results and react to the results as
appropriate.
The following code snippet is an example of a method in an Activity that will start scanning for fingerprints:
Let's discuss each of these parameters in the Authenticate method in a bit more detail:
The first parameter is a crypto object that the fingerprint scanner will use to help authenticate the results of a
fingerprint scan. This object may be null , in which case the application has to blindly trust that nothing has
tampered with the fingerprint results. It is recommended that a CryptoObject be instantiated and provided to
the FingerprintManager rather than null. Creating a CryptObject will explain in detail how to instantiate a
CryptoObject based on a Cipher .
The second parameter is always zero. The Android documentation identifies this as set of flags and is most
likely reserved for future use.
The third parameter, cancellationSignal is an object used to turn off the fingerprint scanner and cancel the
current request. This is an Android CancellationSignal, and not a type from the .NET framework.
The fourth parameter is mandatory and is a class that subclasses the AuthenticationCallback abstract class.
Methods on this class will be invoked to signal to clients when the FingerprintManager has finished and what
the results are. As there is a lot to understand about implementing the AuthenticationCallback , it will be
covered in it's own section.
The fifth parameter is an optional Handler instance. If a Handler object is provided, the FingerprintManager
will use the Looper from that object when processing the messages from the fingerprint hardware. Typically,
one does not need to provide a Handler , the FingerprintManager will use the Looper from the application.
Now that we have seen the Authenticate method, let's examine some of the more important parameters in more
detail. First, we'll look at Responding to Authentication Callbacks, which will discuss how to subclass the
FingerprintManager.AuthenticationCallback, enabling an Android application to react to the results provided by the
fingerprint scanner.
Related Links
CancellationSignal
FingerprintManager.AuthenticationCallback
FingerprintManager.CryptoObject
FingerprintManagerCompat.CryptoObject
FingerprintManager
FingerprintManagerCompat
Creating a CryptoObject
4/12/2018 • 4 minutes to read • Edit Online
The integrity of the fingerprint authentication results is important to an application – it is how the application
knows the identity of the user. It is theoretically possible for third-party malware to intercept and tamper with the
results returned by the fingerprint scanner. This section will discuss one technique for preserving the validity of the
fingerprint results.
The FingerprintManager.CryptoObject is a wrapper around the Java cryptography APIs and is used by the
FingerprintManager to protect the integrity of the authentication request. Typically, a Javax.Crypto.Cipher object is
the mechanism for encrypting the results of the fingerprint scanner. The Cipher object itself will use a key that is
created by the application using the Android keystore APIs.
To understand how these classes all work together, let's first look at the following code which demonstrates how to
create a CryptoObject , and then explain in more detail:
public CryptoObjectHelper()
{
_keystore = KeyStore.GetInstance(KEYSTORE_NAME);
_keystore.Load(null);
}
IKey GetKey()
{
IKey secretKey;
if(!_keystore.IsKeyEntry(KEY_NAME))
{
CreateKey();
}
void CreateKey()
{
KeyGenerator keyGen = KeyGenerator.GetInstance(KeyProperties.KeyAlgorithmAes, KEYSTORE_NAME);
KeyGenParameterSpec keyGenSpec =
new KeyGenParameterSpec.Builder(KEY_NAME, KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt)
.SetBlockModes(BLOCK_MODE)
.SetEncryptionPaddings(ENCRYPTION_PADDING)
.SetUserAuthenticationRequired(true)
.Build();
keyGen.Init(keyGenSpec);
keyGen.GenerateKey();
}
}
The sample code will create a new Cipher for each CryptoObject , using a key that was created by the application.
The key is identified by the KEY_NAME variable that was set in the beginning of the CryptoObjectHelper class. The
method GetKey will try and retrieve the key using the Android Keystore APIs. If the key does not exist, then the
method CreateKey will create a new key for the application.
The cipher is instantiated with a call to Cipher.GetInstance , taking a transformation (a string value that tells the
cipher how to encrypt and decrypt data). The call to Cipher.Init will complete the initialization of the cipher by
providing a key from the application.
It is important to realize that there are some situations where Android may invalidate the key:
A new fingerprint has been enrolled with the device.
There are no fingerprints enrolled with the device.
The user has disabled the screen lock.
The user has changed the screen lock (the type of the screenlock or the PIN/pattern used).
When this happens, Cipher.Init will throw a KeyPermanentlyInvalidatedException . The above sample code will
trap that exception, delete the key, and then create a new one.
The next section will discuss how to create the key and store it on the device.
Once the KeyGenParameterSpec is created, it is used to initialize the KeyGenerator , which will generate a key and
securely store it on the device.
Now that we have seen how to create a CryptoObject , lets move on to see how the
FingerprintManager.AuthenticationCallbacks are used to transfer the results of fingerprint scanner service to an
Android application.
Related Links
Cipher
FingerprintManager.CryptoObject
FingerprintManagerCompat.CryptoObject
KeyGenerator
KeyGenParameterSpec
KeyGenParameterSpec.Builder
KeyPermanentlyInvalidatedException
KeyProperties
AES
RFC 2315 - PCKS #7
Responding to Authentication Callbacks
4/12/2018 • 5 minutes to read • Edit Online
The fingerprint scanner runs in the background on its own thread, and when it is finished it will report the results
of the scan by invoking one method of FingerprintManager.AuthenticationCallback on the UI thread. An Android
application must provide its own handler which extends this abstract class, implementing all the following
methods:
OnAuthenticationError(int errorCode, ICharSequence errString) – Called when there is an unrecoverable error.
There is nothing more an application or user can do to correct the situation except possibly try again.
OnAuthenticationFailed() – This method is invoked when a fingerprint has been detected but not recognized
by the device.
OnAuthenticationHelp(int helpMsgId, ICharSequence helpString) – Called when there is a recoverable error, such
as the finger being swiped to fast over the scanner.
OnAuthenticationSucceeded(FingerprintManagerCompati.AuthenticationResult result) – This is called when a
fingerprint has been recognized.
If a CryptoObject was used when calling Authenticate , it is recommended to call Cipher.DoFinal in
OnAuthenticationSuccessful . DoFinal will throw an exception if the cipher was tampered with or improperly
initialized, indicating that the result of the fingerprint scanner may have been tampered with outside of the
application.
NOTE
It is recommended to keep the callback class relatively light weight and free of application specific logic. The callbacks should
act as a "traffic cop" between the Android application and the results from the fingerprint scanner.
public MyAuthCallbackSample()
{
}
OnAuthenticationFailed is invoked when the fingerprint was successfully scanned but did not match any
fingerprint enrolled with the device.
Related Links
Cipher
AuthenticationCallback
AuthenticationCallback
Fingerprint Authentication Guidance
4/12/2018 • 2 minutes to read • Edit Online
4. Notify the User – An application should display some kind of notification to the user that the fingerprint
scanner is active and awaiting a touch or swipe.
Summary
Fingerprint authentication is a great way to allow a Xamarin.Android application to quickly verify users, making it
easier for users to interact with sensitive features such as in-app purchases. This guide discussed the concepts and
code that is required to incorporate the Android 6.0 fingerprint API's in your Xamarin.Android application.
First we discussed the fingerprint API's themselves, FingerprintManager (and FingerprintManagerCompat ). We
examined how the FingerprintManager.AuthenticationCallbacks abstract class must be extended by an application
and used as an intermediary between the fingerprint hardware and the application itself. Then we examined how to
verify the integrity of the fingerprint scanner results using a Java Cipher object. Finally, we touched a bit on testing
by describing how to enroll a fingerprint on a device and using adb to simulate a fingerprint swipe on an emulator.
If you haven't already done so, you should look at the sample application that accompanies this guide. The
Fingerprint Dialog Sample has been ported from Java to Xamarin.Android and provides another example on how
to add fingerprint authentication to an Android application.
Related Links
Fingerprint Guide Sample App
Fingerprint Dialog Sample
Fingerprint Icon
Enrolling a Fingerprint
4/12/2018 • 2 minutes to read • Edit Online
Requirements
To enroll a fingerprint, you must have an Android device or an emulator running API level 23 (Android 6.0).
The use of the Android Debug Bridge (ADB ) requires familiarity with the command prompt, and the adb
executable must be in the PATH of your Bash, PowerShell, or Command Prompt environment.
5. In the final screen you are prompted to place your finger on the fingerprint scanner:
If you are using an Android device, complete the process by touching a finger to the scanner.
Simulating a Fingerprint Scan on the Emulator
On an Android emulator, it is possible to simulate a fingerprint scan by using the Android Debug Bridge. On OS X
start a Terminal session while on Windows start a command prompt or a Powershell session and run adb :
The value of 1 is the finger_id for the finger that was "scanned". It is a unique integer that you assign for each
virtual fingerprint. In the future when the app is running you can run this same ADB command each time the
emulator prompts you for a fingerprint, you can run the adb command and pass it the finger_id to simulate the
fingerprint scan.
After the fingerprint scan is complete, Android will notify you that the fingerprint has been added:
Summary
This guide covered how to setup a screen lock and enroll a fingerprint on an Android device or in an Android
emulator.
Android Job Scheduler
3/21/2018 • 10 minutes to read • Edit Online
This guide discusses how to schedule background work using the Android Job Scheduler API, which is available on
Android devices running Android 5.0 (API level 21 ) and higher.
Overview
One of the best ways to keep an Android application responsive to the user is to ensure that complex or long
running work is performed in the background. However, it is important that background work will not negatively
impact the user's experience with the device.
For example, a background job might poll a website every three or four minutes to query for changes to a
particular dataset. This seems benign, however it would have a disastrous impact on battery life. The application
will repeatedly wake up the device, elevate the CPU to a higher power state, power up the radios, make the
network requests, and then processing the results. It gets worse because the device will not immediately power
down and return to the low -power idle state. Poorly scheduled background work may inadvertently keep the
device in a state with unnecessary and excessive power requirements. This seemingly innocent activity (polling a
website) will render the device unusable in a relatively short period of time.
Android provides the following APIs to help with performing work in the background but by themselves they are
not sufficient for intelligent job scheduling.
Intent Services – Intent Services are great for performing the work, however they provide no way to schedule
work.
AlarmManager – These APIs only allow work to be scheduled but provide no way to actually perform the
work. Also, the AlarmManager only allows time based constraints, which means raise an alarm at a certain time
or after a certain period of time has elapsed.
Broadcast Receivers – An Android app can setup broadcast receivers to perform work in response to system-
wide events or Intents. However, broadcast receivers don't provide any control over when the job should be run.
Also changes in the Android operating system will restrict when broadcast receivers will work, or the kinds of
work that they can respond to.
There are two key features to efficiently performing background work (sometimes referred to as a background job
or a job):
1. Intelligently scheduling the work – It is important that when an application is doing work in the background
that it does so as a good citizen. Ideally, the application should not demand that a job be run. Instead, the
application should specify conditions that must be met for when the job can run, and then schedule that job with
the operating system that will perform the work when the conditions are met. This allows Android to run the job
to ensure maximum efficiency on the device. For example, network requests may be batched to run all at the
same time to make maximum use of overhead involved with networking.
2. Encapsulating the work – The code to perform the background work should be encapsulated in a discrete
component that can be run independently of the user interface and will be relatively easy to reschedule if the
work fails to complete for some reason.
The Android Job Scheduler is a framework built in to the Android operating system that provides a fluent API to
simplify scheduling background work. The Android Job Scheduler consists of the following types:
The Android.App.Job.JobScheduler is a system service that is used to schedule, execute, and if necessary cancel,
jobs on behalf of an Android application.
An Android.App.Job.JobService is an abstract class that must be extended with the logic that will run the job on
the main thread of the application. This means that the JobService is responsible for how the work is to be
performed asynchronously.
An Android.App.Job.JobInfo object holds the criteria to guide Android when the job should run.
To schedule work with the Android Job Scheduler, a Xamarin.Android application must encapsulate the code in a
class that extends the JobService class. JobService has three lifecycle methods that that can be called during the
lifetime of the job:
bool OnStartJob(JobParameters parameters) – This method is called by the JobScheduler to perform
work, and runs on the main thread of the application. It is the responsibility of the JobService to
asynchronously perform the work and true if there is work remaining, or false if the work is done.
When the JobScheduler calls this method, it will request and retain a wakelock from Android for the
duration of the job. When the job is finished, it is the responsibility of the JobService to tell the
JobScheduler of this fact by call the JobFinished method (described next).
Requirements
The Android Job Scheduler requires Android API level 21 (Android 5.0) or higher.
[Service(Name = "com.xamarin.samples.downloadscheduler.DownloadJob",
Permission = "android.permission.BIND_JOB_SERVICE")]
public class DownloadJob : JobService
{
public override bool OnStartJob(JobParameters jobParams)
{
Task.Run(() =>
{
// Work is happening asynchronously
JobId – this is an int value that is used to identify a job to the JobScheduler . Reusing this value will update
any existing jobs. The value must be unique for the application.
JobService – this parameter is a ComponentName that explicitly identifies the type that the JobScheduler should
use to run a job.
This extension method demonstrates how to create a JobInfo.Builder with an Android Context , such as an
Activity:
public static class JobSchedulerHelpers
{
public static JobInfo.Builder CreateJobBuilderUsingJobId<T>(this Context context, int jobId) where
T:JobService
{
var javaClass = Java.Lang.Class.FromType(typeof(T));
var componentName = new ComponentName(context, javaClass);
return new JobInfo.Builder(jobId, componentName);
}
}
A powerful feature of the Android Job Scheduler is the ability to control when a job runs or under what conditions
a job may run. The following table describes some of the methods on JobInfo.Builder that allow an app to
influence when a job can run:
METHOD DESCRIPTION
SetOverridingDeadline Declares the that the job must run before this time (in
milliseconds) has elapsed.
SetRequiresBatteryNotLow The job may only run when the device is not displaying a "low
battery" warning to the user.
SetRequiresCharging The job may only run when the battery is charging.
The SetBackoffCriteria provides some guidance on how long the JobScheduler should wait before trying to run a
job again. There are two parts to the backoff criteria: a delay in milliseconds (default value of 30 seconds)and type
of back off that should be used (sometimes referred to as the backoff policy or the retry policy). The two policies
are encapsulated in the Android.App.Job.BackoffPolicy enum:
BackoffPolicy.Exponential – An exponential backoff policy will increase the initial backoff value exponentially
after each failure. The first time a job fails, the library will wait the initial interval that is specified before
rescheduling the job – example 30 seconds. The second time the job fails, the library will wait at least 60
seconds before trying to run the job. After the third failed attempt, the library will wait 120 seconds, and so on.
This is the default value.
BackoffPolicy.Linear – This strategy is a linear backoff that the job should be rescheduled to run at set
intervals (until it succeeds). Linear backoff is best suited for work that must be completed as soon as possible or
for problems that will quickly resolve themselves.
For more details on create a JobInfo object, please read Google's documentation for the JobInfo.Builder class.
Passing parameters to a job via the JobInfo
Parameters are passed to a job by creating a PersistableBundle that is passed along with the
Job.Builder.SetExtras method:
Scheduling a job
To schedule a job, a Xamarin.Android application will get a reference to the JobScheduler system service and call
the JobScheduler.Schedule method with the JobInfo object that was created in the previous step.
JobScheduler.Schedule will immediately return with one of two integer values:
if (JobScheduler.ResultSuccess == scheduleResult)
{
Snackbar.Make(FindViewById(Android.Resource.Id.Content), Resource.String.jobscheduled_success,
Snackbar.LengthShort);
}
else
{
Snackbar.Make(FindViewById(Android.Resource.Id.Content), Resource.String.jobscheduled_failure,
Snackbar.LengthShort);
}
Cancelling a job
It is possible to cancel all the jobs that have been scheduled, or just a single job using the
JobsScheduler.CancelAll() method or the JobScheduler.Cancel(jobId) method:
Related Links
Intelligent Job-Scheduling
JobScheduler API reference
Scheduling jobs like a pro with JobScheduler
Android Battery and Memory Optimizations - Google I/O 2016 (video)
Android JobScheduler - René Ruppert - Xamarin University
Firebase Job Dispatcher
6/6/2018 • 13 minutes to read • Edit Online
This guide discusses how to schedule background work using the Firebase Job Dispatcher library from Google.
Overview
One of the best ways to keep an Android application responsive to the user is to ensure that complex or long
running work is performed in the background. However, it is important that background work will not negatively
impact the user's experience with the device.
For example, a background job might poll a website every three or four minutes to query for changes to a
particular dataset. This seems benign, however it would have a disastrous impact on battery life. The application
will repeatedly wake up the device, elevate the CPU to a higher power state, power up the radios, make the
network requests, and then processing the results. It gets worse because the device will not immediately power
down and return to the low -power idle state. Poorly scheduled background work may inadvertently keep the
device in a state with unnecessary and excessive power requirements. This seemingly innocent activity (polling a
website) will render the device unusable in a relatively short period of time.
Android provides the following APIs to help with performing work in the background but by themselves they are
not sufficient for intelligent job scheduling.
Intent Services – Intent Services are great for performing the work, however they provide no way to schedule
work.
AlarmManager – These APIs only allow work to be scheduled but provide no way to actually perform the
work. Also, the AlarmManager only allows time based constraints, which means raise an alarm at a certain time
or after a certain period of time has elapsed.
JobScheduler – The JobSchedule is a great API that works with the operating system to schedule jobs.
However, it is only available for those Android apps that target API level 21 or higher.
Broadcast Receivers – An Android app can setup broadcast receivers to perform work in response to system-
wide events or Intents. However, broadcast receivers don't provide any control over when the job should be
run. Also changes in the Android operating system will restrict when broadcast receivers will work, or the kinds
of work that they can respond to.
There are two key features to efficiently performing background work (sometimes referred to as a background job
or a job):
1. Intelligently scheduling the work – It is important that when an application is doing work in the background
that it does so as a good citizen. Ideally, the application should not demand that a job be run. Instead, the
application should specify conditions that must be met for when the job can run, and then schedule that work
to run when the conditions are met. This allows Android to intelligently perform work. For example, network
requests may be batched to run all at the same time to make maximum use of overhead involved with
networking.
2. Encapsulating the work – The code to perform the background work should be encapsulated in a discrete
component that can be run independently of the user interface and will be relatively easy to reschedule if the
work fails to complete for some reason.
The Firebase Job Dispatcher is a library from Google that provides a fluent API to simplify scheduling background
work. It is intended to be the replacement for Google Cloud Manager. The Firebase Job Dispatcher consists of the
following APIs:
A Firebase.JobDispatcher.JobService is an abstract class that must be extended with the logic that will run in
the background job.
A Firebase.JobDispatcher.JobTrigger declares when the job should be started. This is typically expressed as a
window of time, for example, wait at least 30 seconds before starting the job, but run the job within 5 minutes.
A Firebase.JobDispatcher.RetryStrategy contains information about what should be done when a job fails to
execute properly. The retry strategy specifies how long to wait before trying to run the job again.
A Firebase.JobDispatcher.Constraint is an optional value that describes a condition that must be met before
the job can run, such as the device is on an unmetered network or charging.
The Firebase.JobDispatcher.Job is an API that unifies the previous APIs in to a unit-of-work that can be
scheduled by the JobDispatcher . The Job.Builder class is used to instantiate a Job .
A Firebasee.JobDispatcher.JobDispatcher uses the previous three APIs to schedule the work with the operating
system and to provide a way to cancel jobs, if necessary.
To schedule work with the Firebase Job Dispatcher, a Xamarin.Android application must encapsulate the code in a
type that extends the JobService class. JobService has three lifecycle methods that that can be called during the
lifetime of the job:
bool OnStartJob(IJobParameters parameters) – This method is where the work will occur and should always be
implemented. It runs on the main thread. This method will return true if there is work remaining, or false if
the work is done.
bool OnStopJob(IJobParameters parameters) – This is called when the job is stopped for some reason. It should
return true if the job should be rescheduled for later.
JobFinished(IJobParameters parameters, bool needsReschedule) – This method is called when the JobService
has finished any asynchronous work.
To schedule a job, the application will instantiate a JobDispatcher object. Then, a Job.Builder is used to create a
Job object, which is provided to the JobDispatcher which will try and schedule the job to run.
This guide will discuss how to add the Firebase Job Dispatcher to a Xamarin.Android application and use it to
schedule background work.
Requirements
The Firebase Job Dispatcher requires Android API level 9 or higher. The Firebase Job Dispatcher library relies on
some components provided by Google Play Services; the device must have Google Play Services installed.
[Service(Name = "com.xamarin.fjdtestapp.DemoJob")]
[IntentFilter(new[] {FirebaseJobServiceIntent.Action})]
public class DemoJob : JobService
{
static readonly string TAG = "X:DemoService";
});
Creating a FirebaseJobDispatcher
Before any work can be scheduled, it is necessary to create a Firebase.JobDispatcher.FirebaseJobDispatcher object.
The FirebaseJobDispatcher is responsible for scheduling a JobService . The following code snippet is one way to
create an instance of the FirebaseJobDispatcher :
In the previous code snippet, the GooglePlayDriver is class that helps the FirebaseJobDispatcher interact with
some of the scheduling APIs in Google Play Services on the device. The parameter context is any Android
Context , such as an Activity. Currently the GooglePlayDriver is the only IDriver implementation in the Firebase
Job Dispatcher library.
The Xamarin.Android binding for the Firebase Job Dispatcher provides an extension method to create a
FirebaseJobDispatcher from the Context :
Once the FirebaseJobDispatcher has been instantiated, it is possible to create a Job and run the code in the
JobService class. The Job is created by a Job.Builder object and will be discussed in the next section.
Creating a Firebase.JobDispatcher.Job with the Job.Builder
The Firebase.JobDispatcher.Job class is responsible for encapsulating the meta-data necessary to run a
JobService . A Job contains information such as any constraint that must be met before the job can run, if the
Job is recurring, or any triggers that will cause the job to be run. As a bare minimum, a Job must have a tag (a
unique string that identifies the job to the FirebaseJobDispatcher ) and the type of the JobService that should be
run. The Firebase Job Dispatcher will instantiate the JobService when it is time to run the job. A Job is created by
using an instance of the Firebase.JobDispatcher.Job.JobBuilder class.
The following code snippet is the simplest example of how to create a Job using the Xamarin.Android binding:
The Job.Builder will perform some basic validation checks on the input values for the job. An exception will be
thrown if it not possible for the Job.Builder to create a Job . The Job.Builder will create a Job with the
following defaults:
A Job 's lifetime (how long it will be scheduled to run) is only until the device reboots – once the device reboots
the Job is lost.
A Job is not recurring – it will only run once.
A Job will be scheduled to run as soon as possible.
The default retry strategy for a Job is to use an exponential backoff (discussed on more detail below in the
section Setting a RetryStrategy)
Scheduling a job
After creating the Job , it needs to be scheduled with the FirebaseJobDispatcher before it is run. There are two
methods for scheduling a Job :
// This will throw an exception if there was a problem scheduling the job
dispatcher.MustSchedule(myJob);
// This method will not throw an exception; an integer result value is returned
int scheduleResult = dispatcher.Schedule(myJob);
The value returned by FirebaseJobDispatcher.Schedule will be one of the following integer values:
– The Job was successfully scheduled.
FirebaseJobDispatcher.ScheduleResultSuccess
FirebaseJobDispatcher.ScheduleResultUnknownError – Some unknown problem occurred which prevented the
Job from being scheduled.
FirebaseJobDispatcher.ScheduleResultNoDriverAvailable – An invalid IDriver was used or the IDriver was
somehow unavailable.
FirebaseJobDispatcher.ScheduleResultUnsupportedTrigger – The Trigger was not supported.
FirebaseJobDispatcher.ScheduleResultBadService – The service is not configured correctly or is unavailable.
Configuring a job
It is possible to customize a job. Examples of how a job may be customized include the following:
Passing Parameters to a Job – A Job may require additional values to perform its work, for example
downloading a file.
Set Constraints – It may be necessary to only run a job when certain conditions are met. For example, only run
a Job when the device is charging.
Specify when a Job should run – The Firebase Job Dispatcher allows applications to specify a time when the
job should run.
Declare a retry strategy for failed jobs – A retry strategy provides guidance to the FirebaseJobDispatcher on
what to do with Jobs that fail to complete.
Each of these topics will be discussed more in the following sections.
Passing jarameters to a job
Parameters are passed to a job by creating a Bundle that is passed along with the Job.Builder.SetExtras method:
The Bundle is accessed from the IJobParameters.Extras property on the OnStartJob method:
Setting constraints
Constraints can help reduces costs or battery drain on the device. The Firebase.JobDispatcher.Constraint class
defines these constraints as integer values:
Constraint.OnUnmeteredNetwork – Only run the job when the device is connected to an unmetered network. This
is useful to prevent the user from incurring data charges.
Constraint.OnAnyNetwork – Run the job on whatever network the device is connected to. If specified along with
Constraint.OnUnmeteredNetwork , this value will take priority.
Constraint.DeviceCharging – Run the job only when the device is charging.
The JobTrigger provides guidance to the operating system about when the job should start. A JobTrigger has an
executing window that defines a scheduled time for when the Job should run. The execution window has a start
window value and an end window value. The start window is the number of seconds that the device should wait
before running the job and the end window value is the maximum number of seconds to wait before running the
Job .
Cancelling a job
It is possible to cancel all the jobs that have been scheduled, or just a single job using the
FirebaseJobDispatcher.CancelAll() method or the FirebaseJobDispatcher.Cancel(string) method:
Summary
This guide discussed how to use the Firebase Job Dispatcher to intelligently perform work in the background. It
discussed how to encapsulate the work to be performed as a JobService and how to use the
FirebaseJobDispatcher to schedule that work, specifying the criteria with a JobTrigger and how failures should be
handled with a RetryStrategy .
Related Links
Xamarin.Firebase.JobDispatcher on NuGet
firebase-job-dispatcher on GitHub
Xamarin.Firebase.JobDispatcher Binding
Intelligent Job-Scheduling
Android Battery and Memory Optimizations - Google I/O 2016 (video)
Fragments
4/12/2018 • 3 minutes to read • Edit Online
Android 3.0 introduced Fragments, showing how to support more flexible designs for the many different screen
sizes found on phones and tablets. This article will cover how to use Fragments to develop Xamarin.Android
applications, and also how to support Fragments on pre-Android 3.0 (API Level 11 ) devices.
Fragments Overview
The larger screen sizes found on most tablets added an extra layer of complexity to Android development—a
layout designed for the small screen does not necessarily work as well for larger screens, and vice-versa. To reduce
the number of complications that this introduced, Android 3.0 added two new features, Fragments and Support
Packages.
Fragments can be thought of as user interface modules. They let the developer divide up the user interface into
isolated, reusable parts that can be run in separate Activities. At run time, the Activities themselves will decide
which Fragments to use.
Support Packages were originally called Compatibility Libraries and allowed Fragments to be used on devices
that run versions of Android prior to Android 3.0 (API Level 11).
For example, the image below illustrates how a single application uses Fragments across varying device form
factors.
Fragment A contains a list, while Fragment B contains details for an item selected in that list. When the
application is run on a tablet, it can display both Fragments on the same Activity. When the same application is
run on a handset (with its smaller screen size), the Fragments are hosted in two separate Activities. Fragment A
and Fragment B are the same on both form factors, but the Activities that host them are different.
To help an Activity coordinate and manage all these Fragments, Android introduced a new class called the
FragmentManager. Each Activity has its own instance of a FragmentManager for adding, deleting, and finding
hosted Fragments. The following diagram illustrates the relationship between Fragments and Activities:
In some regards, Fragments can be thought of as composite controls or as mini-Activities. They bundle up pieces
of UI into reusable modules that can then be used independently by developers in Activities. A Fragment does
have a view hierarchy—just like an Activity—but, unlike an Activity, it can be shared across screens. Views differ
from Fragments in that Fragments have their own lifecycle; views do not.
While the Activity is a host to one or more Fragments, it is not directly aware of the Fragments themselves.
Likewise, Fragments are not directly aware of other Fragments in the hosting Activity. However, Fragments and
Activities are aware of the FragmentManager in their Activity. By using the FragmentManager , it is possible for an
Activity or a Fragment to obtain a reference to a specific instance of a Fragment, and then call methods on that
instance. In this way, the Activity or Fragments can communicate and interact with other Fragments.
This guide contains comprehensive coverage about how to use Fragments, including:
Creating Fragments – How to create a basic Fragment and key methods that must be implemented.
Fragment Management and Transactions – How to manipulate Fragments at run time.
Android Support Package – How to use the libraries that allow Fragments to be used on older versions of
Android.
Requirements
Fragments are available in the Android SDK starting with API level 11 (Android 3.0), as shown in the following
screenshot:
Fragments are available in Xamarin.Android 4.0 and higher. A Xamarin.Android application must target at least
API level 11 (Android 3.0) or higher in order to use Fragments. The Target Framework may be set in the project
Properties as shown below:
It is possible to use Fragments in older versions of Android by using the Android Support Package and
Xamarin.Android 4.2 or higher. How to do this is covered in more detail in the documents of this section.
Related Links
Honeycomb Gallery (sample)
Fragments
Support Package
MOTODEV Webinar: Introducing Fragments
Implementing fragments - walkthrough
5/7/2018 • 2 minutes to read • Edit Online
Fragments are self-contained, modular components that can help address the complexity of Android apps that
target devices with a variety of screen sizes. This article walks through how to create and use fragments when
developing Xamarin.Android applications.
Overview
In this section, you'll walk through how to create and use fragments in a Xamarin.Android application. This
application will display the titles of several plays by William Shakespeare in a list. When the user taps on the title of
a play, then the app will display a quote from that play in a separate activity:
When the phone is rotated to landscape mode, the appearance of the app will change: both the list of plays and
quotes will appear in the same activity. When a play is selected, the quote will be display in the same activity:
Finally, if the app is running on a tablet:
This sample application can easily adapt to the different form factors and orientations with minimal code changes
by using fragments and Alternate Layouts.
The data for the application will exist in two string arrays that are hardcoded in the app as C# string arrays. Each of
the arrays will serve as the data source for one fragment. One array will hold the name of some plays by
Shakespeare, and the other array will hold a quote from that play. When the app starts up, it will display the play
names in a ListFragment . When the user clicks on a play in the ListFragment , the app will start up another activity
which will display the quote.
The user interface for the app will consist of two layouts, one for portrait and one for landscape mode. At run time,
Android will determine what layout to load based on the orientation of the device and will provide that layout to
the Activity to render. All of the logic for responding to user clicks and displaying the data will be contained in
fragments. The Activities in the app exist only as containers that will host the fragments.
This walkthrough will be broken down into two guides. The first part will focus on the core parts of the application.
A single set of layouts (optimized for portrait mode) will be created, along with two fragments and two Activities:
1. MainActivity This is the startup Activity for the app.
2. TitlesFragment This fragment will display a list of titles of plays that were written by William Shakespeare. It
will be hosted by MainActivity .
3. PlayQuoteActivity TitlesFragment will start the PlayQuoteActivity in response to the user selecting a play in
TitlesFragment .
4. PlayQuoteFragment This fragment will display a quote from a play by William Shakespeare. It will be hosted by
PlayQuoteActivity .
The second part of this walkthrough will discuss adding an alternate layout (optimized for landscape mode) which
will display both fragments on the screen. Also, some minor code changes will be made to the code so that the app
will adapt its behavior to the number of fragments that are concurrently displayed on the screen.
Related Links
FragmentsWalkthrough (sample)
Designer Overview
Implementing Fragments
Support Package
Fragments walkthrough – phone]
5/7/2018 • 13 minutes to read • Edit Online
This is the first part of a walkthrough that will create a Xamarin.Android app that targets an Android device in
portrait orientation. This walkthrough will discuss how to create fragments in Xamarin.Android and how to add
them to a sample.
Shakespeare.Titles This array will hold a list of plays from William Shakespeare. This is the data source for
the TitlesFragment .
Shakespeare.Dialogue This array will hold a list of quotes from one of the plays contained in
Shakespeare.Titles . This is the data source for the PlayQuoteFragment .
Add a new C# class to the FragmentSample project and name it Shakespeare.cs. Inside this file, create a new
C# class called Shakespeare with the following contents
class Shakespeare
{
public static string[] Titles = {
"Henry IV (1)",
"Henry V",
"Henry VIII",
"Richard II",
"Richard III",
"Merchant of Venice",
"Othello",
"King Lear"
};
Then, change the code for the fragment to resemble this snippet:
public class PlayQuoteFragment : Fragment
{
public int PlayId => Arguments.GetInt("current_play_id", 0);
return scroller;
}
}
It is a common pattern in Android apps to provide a factory method that will instantiate a fragment. This ensures
that the fragment will be created with the necessary parameters for proper functioning. In this walkthrough, the
app is expected to use the PlayQuoteFragment.NewInstance method to create a new fragment each time a quote is
selected. The NewInstance method will take a single parameter – the index of the quote to display.
The OnCreateView method will be invoked by Android when it is time to render the fragment on the screen. It will
return an Android View object that is the fragment. This fragment does not use a layout file to create a view.
Instead, it will programmatically create the view by instantiating a TextView to hold the quote, and will display
that widget in a ScrollView.
NOTE
Fragment sub-classes must have a public default constructor that has no parameters.
[Activity(Label = "PlayQuoteActivity")]
public class PlayQuoteActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
When PlayQuoteActivity is created, it will instantiate a new PlayQuoteFragment and load that fragment in its root
view in the context of a FragmentTransaction . Notice that this activity does not load an Android layout file for its
user interface. Instead, a new PlayQuoteFragment is added to the root view of the application. The resource
identifier Android.Resource.Id.Content is used to refer to the root view of an Activity without knowing its specific
identifier.
5. Create TitlesFragment
The TitlesFragment will subclass a specialized fragment known as a ListFragment which encapsulates the logic
for displaying a ListView in a fragment. A ListFragment exposes a ListAdapter property (used by the ListView
to display its contents) and an event handler named OnListItemClick which allows the fragment to respond to
clicks on a row that is displayed by the ListView .
To get started, add a new fragment to the project and name it TitlesFragment:
Visual Studio
Visual Studio for Mac
Edit the code inside the fragment:
public TitlesFragment()
{
// Being explicit about the requirement for a default constructor.
}
if (savedInstanceState != null)
{
selectedPlayId = savedInstanceState.GetInt("current_play_id", 0);
}
}
When the Activity is created Android will invoke the OnActivityCreated method of the fragment; this is where the
list adapter for the ListView is created. The ShowQuoteFromPlay method will start an instance of the
PlayQuoteActivity to display the quote for the selected play.
NOTE
The class attribute is a valid substitute for android:name . There is no formal guidance on which form is preferred, there
are many examples of code bases that will use class interchangeably with android:name .
There are no code changes required for MainActivity. The code in that class should be very similar to this snippet:
The Fragments Walkthrough – Part 1 demonstrated how to create and use fragments in an Android app that
targets the smaller screens on a phone. The next step in this walkthrough is to modify the application to take
advantage of the extra horizontal space on tablet – there will be one activity that will always be the list of plays (the
TitlesFragment ) and PlayQuoteFragment will be dynamically added to the Activity in response to a selection made
by the user:
Phones that are running in landscape mode will also benefit from this enhancement:
After creating the alternate layout, edit the source of the file Resources/layout-land/activity_main.axml so that
it matches this XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/two_fragments_layout"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment android:name="FragmentSample.TitlesFragment"
android:id="@+id/titles"
android:layout_weight="1"
android:layout_width="0px"
android:layout_height="match_parent" />
<FrameLayout android:id="@+id/playquote_container"
android:layout_weight="1"
android:layout_width="0px"
android:layout_height="match_parent"
/>
</LinearLayout>
The root view of the activity is given the resource ID two_fragments_layout and has two sub-views, a fragment
and a FrameLayout . While the fragment is statically loaded, the FrameLayout acts as a "placeholder" that will be
replaced at run-time by the PlayQuoteFragment . Each time a new play is selected in the TitlesFragment , the
playquote_container will be updated with a new instance of the PlayQuoteFragment .
Each of the sub-views will occupy the full height of their parent. The width of each subview is controlled by the
android:layout_weight and android:layout_width attributes. In this example, each subview will occupy 50% of
width provide by the parent. See Google's document on the LinearLayout for details about Layout Weight.
2. Changes to TitlesFragment
Once the alternate layout has been created, it is necessary to update TitlesFragment . When the app is displaying
the two fragments on one activity, then TitlesFragment should load the PlayQuoteFragment in the parent Activity.
Otherwise, TitlesFragment should launch the PlayQuoteActivity which host the PlayQuoteFragment . A boolean
flag will help TitlesFragment determine which behavior it should use. This flag will be initialized in the
OnActivityCreated method.
bool showingTwoFragments;
Then, add the following code snippet to OnActivityCreated to initialize the variable:
If the device is running in landscape mode, then the FrameLayout with the resource ID playquote_container will be
visible on the screen, so showingTwoFragments will be initialized to true . If the device is running in portrait mode,
then playquote_container will not be on the screen, so showingTwoFragments will be false .
The ShowPlayQuote method will need to change how it displays a quote – either in a fragment or launch a new
activity. Update the ShowPlayQuote method to load a fragment when showing two fragments, otherwise it should
launch an Activity:
FragmentTransaction ft = FragmentManager.BeginTransaction();
ft.Replace(Resource.Id.playquote_container, quoteFrag);
ft.Commit();
}
}
else
{
var intent = new Intent(Activity, typeof(PlayQuoteActivity));
intent.PutExtra("current_play_id", playId);
StartActivity(intent);
}
}
If the user has selected a play that is different from the one that is currently being displayed in PlayQuoteFragment ,
then a new PlayQuoteFragment is created and will replace the contents of the playquote_container within the
context of a FragmentTransaction .
Complete code for TitlesFragment
After completing all the previous changes to TitlesFragment , the complete class should match this code:
if (savedInstanceState != null)
{
selectedPlayId = savedInstanceState.GetInt("current_play_id", 0);
}
FragmentTransaction ft = FragmentManager.BeginTransaction();
ft.Replace(Resource.Id.playquote_container, quoteFrag);
ft.AddToBackStack(null);
ft.SetTransition(FragmentTransit.FragmentFade);
ft.Commit();
}
}
else
{
var intent = new Intent(Activity, typeof(PlayQuoteActivity));
intent.PutExtra("current_play_id", playId);
StartActivity(intent);
}
}
}
3. Changes to PlayQuoteActivity
There is one final detail to take care of: PlayQuoteActivity is not necessary when the device is in landscape mode.
If the device is in landscape mode the PlayQuoteActivity should not be visible. Update the OnCreate method of
PlayQuoteActivity so that it will close itself. This code is the final version of PlayQuoteActivity.OnCreate :
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
if (Resources.Configuration.Orientation == Android.Content.Res.Orientation.Landscape)
{
Finish();
}
This modification adds a check for the device orientation. If it is in landscape mode, then PlayQuoteActivity will
close itself.
To create a Fragment, a class must inherit from Android.App.Fragment and then override the OnCreateView method.
OnCreateView will be called by the hosting Activity when it is time to put the Fragment on the screen, and will
return a View . A typical OnCreateView will create this View by inflating a layout file and then attaching it to a
parent container. The container's characteristics are important as Android will apply the layout parameters of the
parent to the UI of the Fragment. The following example illustrates this:
The code above will inflate the view Resource.Layout.Example_Fragment , and add it as a child view to the ViewGroup
container.
NOTE
Fragment sub-classes must have a public default no argument constructor.
This next snippet shows how to declare a fragment by using the android:name attribute to identify the Fragment
class :
<?xml version="1.0" encoding="utf-8"?>
<fragment android:name="com.xamarin.sample.fragments.TitlesFragment"
android:id="@+id/titles_fragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
When the Activity is being created, Android will instantiate each Fragment specified in the layout file and insert the
view that is created from OnCreateView in place of the Fragment element. Fragments that are declaratively added
to an Activity are static and will remain on the Activity until it is destroyed; it is not possible to dynamically replace
or remove such a Fragment during the lifetime of the Activity to which it is attached.
Each Fragment must be assigned a unique identifier:
android:id – As with other UI elements in a layout file, this is a unique ID.
android:tag – This attribute is a unique string.
If neither of the previous two methods is used, then the Fragment will assume the ID of the container view. In the
following example where neither android:id nor android:tag is provided, Android will assign the ID
fragment_container to the Fragment:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="+@id/fragment_container"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment class="com.example.android.apis.app.TitlesFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
OR
Fragment Lifecycle
Fragments have their own lifecycle that is somewhat independent of, but still affected by, the lifecycle of the hosting
Activity. For example, when an Activity pauses, all of its associated Fragments are paused. The following diagram
outlines the lifecycle of the Fragment.
Fragment Creation Lifecycle Methods
The list below shows the flow of the various callbacks in the lifecycle of a Fragment as it is being created:
OnInflate() – Called when the Fragment is being created as part of a view layout. This may be called
immediately after the Fragment is created declaratively from an XML layout file. The Fragment is not
associated with its Activity yet, but the Activity, Bundle, and AttributeSet from the view hierarchy are
passed in as parameters. This method is best used for parsing the AttributeSet and for saving the attributes
that might be used later by the Fragment.
OnAttach() – Called after the Fragment is associated with the Activity. This is the first method to be run
when the Fragment is ready to be used. In general, Fragments should not implement a constructor or
override the default constructor. Any components that are required for the Fragment should be initialized in
this method.
OnCreate() – Called by the Activity to create the Fragment. When this method is called, the view hierarchy
of the hosting Activity may not be completely instantiated, so the Fragment should not rely on any parts of
the Activity's view hierarchy until later on in the Fragment's lifecycle. For example, do not use this method to
perform any tweaks or adjustments to the UI of the application. This is the earliest time at which the
Fragment may begin gathering the data that it needs. The Fragment is running in the UI thread at this point,
so avoid any lengthy processing, or perform that processing on a background thread. This method may be
skipped if SetRetainInstance(true) is called. This alternative will be described in more detail below.
OnCreateView()– Creates the view for the Fragment. This method is called once the Activity's OnCreate()
method is complete. At this point, it is safe to interact with the view hierarchy of the Activity. This method
should return the view that will be used by the Fragment.
OnActivityCreated() – Called after Activity.OnCreate has been completed by the hosting Activity. Final
tweaks to the user interface should be performed at this time.
OnStart() – Called after the containing Activity has been resumed. This makes the Fragment visible to the
user. In many cases, the Fragment will contain code that would otherwise be in the OnStart() method of an
Activity.
OnResume() – This is the last method called before the user can interact with the Fragment. An example of
the kind of code that should be performed in this method would be enabling features of a device that the
user may interact with, such as the camera that the location services. Services such as these can cause
excessive battery drain, though, and an application should minimize their use to preserve battery life.
Fragment Destruction Lifecycle Methods
The next list explains the lifecycle methods that are called as a Fragment is being destroyed:
OnPause() – The user is no longer able to interact with the Fragment. This situation exists because some
other Fragment operation is modifying this Fragment, or the hosting Activity is paused. It is possible that the
Activity hosting this Fragment might still be visible, that is, the Activity in focus is partially transparent or
does not occupy the full screen. When this method becomes active, it's the first indication that the user is
leaving the Fragment. The Fragment should save any changes.
OnStop()– The Fragment is no longer visible. The host Activity may be stopped, or a Fragment operation is
modifying it in the Activity. This callback serves the same purpose as Activity.OnStop.
OnDestroyView() – This method is called to clean up resources associated with the view. This is called when
the view associated with the Fragment has been destroyed.
OnDestroy() – This method is called when the Fragment is no longer in use. It is still associated with the
Activity, but the Fragment is no longer functional. This method should release any resources that are in use
by the Fragment, such as a SurfaceView that might be used for a camera. This method may be skipped if
SetRetainInstance(true) is called. This alternative will be described in more detail below.
OnDetach() – This method is called just before the Fragment is no longer associated with the Activity. The
view hierarchy of the Fragment no longer exists, and all resources that are used by the Fragment should be
released at this point.
Using SetRetainInstance
It is possible for a Fragment to specify that it should not be completely destroyed if the Activity is being re-created.
The Fragment class provides the method SetRetainInstance for this purpose. If true is passed to this method,
then when the Activity is restarted, the same instance of the Fragment will be used. If this happens, then all callback
methods will be invoked except the OnCreate and OnDestroy lifecycle callbacks. This process is illustrated in the
lifecycle diagram shown above (by the green dotted lines).
Overriding OnSaveInstanceState is an appropriate mechanism for saving transient data in a Fragment across
orientation changes, such as the current_choice value in the above example. However, the default implementation
of OnSaveInstanceState takes care of saving transient data in the UI for every view that has an ID assigned. For
example, look at an application that has an EditText element defined in XML as follows:
<EditText android:id="@+id/myText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
Bundle Limitations
Although using OnSaveInstanceState makes it easy to save transient data, use of this method has some limitations:
If the Fragment is not added to the back stack, then its state will not be restored when the user presses the
Back button.
When the Bundle is used to save data, that data is serialized. This can lead to processing delays.
The menu in the previous code snippet is inflated from the following XML, located in the file
menu_fragment_vehicle_list.xml :
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/add_vehicle"
android:icon="@drawable/ic_menu_add_data"
android:title="@string/add_vehicle" />
</menu>
Next, the Fragment must call SetHasOptionsMenu(true) . The call to this method announces to Android that the
Fragment has menu items to contribute to the option menu. Unless the call to this method is made, the menu items
for the Fragment will not be added to the Activity's option menu. This is typically done in the lifecycle method
OnCreate() , as shown in the next code snippet:
To help with managing Fragments, Android provides the FragmentManager class. Each Activity has an instance of
Android.App.FragmentManager that will find or dynamically change its Fragments. Each set of these changes is
known as a transaction, and is performed by using one of the APIs contained in the class
Android.App.FragmentTransation , which is managed by the FragmentManager . An Activity may start a transaction
like this:
These changes to the Fragments are performed in the FragmentTransaction instance by using methods such as
Add() , Remove(), and Replace(). The changes are then applied by using Commit() . The changes in a transaction
are not performed immediately. Instead, they are scheduled to run on the Activity's UI thread as soon as possible.
The following example shows how to add a Fragment to an existing container:
The Fragments API provides other subclasses that encapsulate some of the more common functionality found in
applications. These subclasses are:
ListFragment – This Fragment is used to display a list of items bound to a datasource such as an array or a
cursor.
DialogFragment – This Fragment is used as a wrapper around a dialog. The Fragment will display the
dialog on top of its Activity.
PreferenceFragment – This Fragment is used to show Preference objects as lists.
The ListFragment
The ListFragment is very similar in concept and functionality to the ListActivity ; it is a wrapper that hosts a
ListView in a Fragment. The image below shows a ListFragment running on a tablet and a phone:
When setting the , it is important to use the ListFragment.ListAdapter property, and not the
ListAdapter
ListView.ListAdapter property. Using ListView.ListAdapter will cause important initialization code to be skipped.
Responding to User Selection
To respond to user selections, an application must override the OnListItemClick method. The following example
shows one such possibility:
In the code above, when the user selects an item in the ListFragment , a new Fragment is displayed in the hosting
Activity, showing more details about the item that was selected.
DialogFragment
The DialogFragment is a Fragment that is used to display a dialog object inside of a Fragment that will float on top
of the Activity's window. It is meant to replace the managed dialog APIs (starting in Android 3.0). The following
screenshot shows an example of a DialogFragment :
A DialogFragment ensures that the state between the Fragment and the dialog remain consistent. All interactions
and control of the dialog object should happen through the DialogFragment API, and not be made with direct calls
on the dialog object. The DialogFragment API provides each instance with a Show() method that is used to display
a Fragment. There are two ways to get rid of a Fragment:
Call DialogFragment.Dismiss() on the DialogFragment instance.
Display another DialogFragment .
To create a DialogFragment , a class inherits from Android.App.DialogFragment, and then overrides one of the
following two methods:
OnCreateView – This creates and returns a view.
OnCreateDialog – This creates a custom dialog. It is typically used to show an AlertDialog. When
overriding this method, it is not necessary to override OnCreateView .
A Simple DialogFragment
The following screenshot shows a simple DialogFragment that has a TextView and two Button s:
The TextView will display the number of times that the user has clicked one button in the DialogFragment , while
clicking the other button will close the Fragment. The code for DialogFragment is:
view.FindViewById<Button>(Resource.Id.dialog_button).Click += delegate
{
textView.Text = "You clicked the button " + _clickCount++ + " times.";
};
Displaying a Fragment
Like all Fragments, a DialogFragment is displayed in the context of a FragmentTransaction .
The Show() method on a DialogFragment takes a FragmentTransaction and a string as an input. The dialog will
be added to the Activity, and the FragmentTransaction committed.
The following code demonstrates one possible way an Activity may use the Show() method to show a
DialogFragment :
Dismissing a Fragment
Calling Dismiss() on an instance of a DialogFragment causes a Fragment to be removed from the Activity and
commits that transaction. The standard Fragment lifecycle methods that are involved with the destruction of a
Fragment will be called.
Alert Dialog
Instead of overriding OnCreateView , a DialogFragment may instead override OnCreateDialog . This allows an
application to create an AlertDialog that is managed by a Fragment. The following code is an example that uses the
AlertDialog.Builder to create a Dialog :
public class AlertDialogFragment : DialogFragment
{
public override Dialog OnCreateDialog(Bundle savedInstanceState)
{
EventHandler<DialogClickEventArgs> okhandler;
var builder = new AlertDialog.Builder(Activity)
.SetMessage("This is my dialog.")
.SetPositiveButton("Ok", (sender, args) =>
{
// Do something when this button is clicked.
})
.SetTitle("Custom Dialog");
return builder.Create();
}
}
PreferenceFragment
To help manage preferences, the Fragments API provides the PreferenceFragment subclass. The
PreferenceFragment is similar to the PreferenceActivity – it will show a hierarchy of preferences to the user in a
Fragment. As the user interacts with the preferences, they will be automatically saved to SharedPreferences. In
Android 3.0 or higher applications, use the PreferenceFragment to deal with preferences in applications. The
following picture shows an example of a PreferenceFragment :
Create A Preference Fragment from a Resource
The preference Fragment may be inflated from an XML resource file by using the
PreferenceFragment.AddPreferencesFromResource method. A logical place to call this method in the lifecycle of
the Fragment would be in the OnCreate method.
The PreferenceFragment pictured above was created by loading a resource from XML. The resource file is:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
</PreferenceCategory>
<EditTextPreference android:key="edittext_preference"
android:title="EditText Preference Title"
android:summary="EditText Preference Summary"
android:dialogTitle="Edit Text Preferrence Dialog Title" />
</PreferenceCategory>
<!-- This PreferenceScreen tag serves as a screen break (similar to page break
in word processing). Like for other preference types, we assign a key
here so it is able to save and restore its instance state. -->
<PreferenceScreen android:key="screen_preference"
android:title="Title Screen Preferences"
android:summary="Summary Screen Preferences">
<!-- You can place more preferences here that will be shown on the next screen. -->
<CheckBoxPreference android:key="next_screen_checkbox_preference"
android:title="Next Screen Toggle Preference Title"
android:summary="Next Screen Toggle Preference Summary" />
</PreferenceScreen>
<intent android:action="android.intent.action.VIEW"
android:data="http://www.android.com" />
</PreferenceScreen>
</PreferenceCategory>
</PreferenceScreen>
Android will look at the class MyActivityWithPreference . The class must be adorned with the MetaDataAttribute, as
shown in the following code snippet:
The MetaDataAttribute declares an XML resource file that the PreferenceFragment will use to inflate the preference
hierarchy. If the MetatDataAttribute is not provided, then an exception will be thrown at run time. When this code
runs, the PreferenceFragment appears as in the following screenshot:
Providing Backwards Compatibility with the Android
Support Package
4/12/2018 • 2 minutes to read • Edit Online
The usefulness of Fragments would be limited without backwards compatibility with pre-Android 3.0 (API Level
11) devices. To provide this capability, Google introduced the Support Library (originally called the Android
Compatibility Library when it was released) which backports some of the APIs from newer versions of Android to
older versions of Android. It is the Android Support Package that enables devices running Android 1.6 (API level 4)
to Android 2.3.3. (API level 10).
NOTE
Only the ListFragment and the DialogFragment are available via the Android Support Package. None of the other
Fragment subclasses, such as the PreferenceFragment, are supported in the Android Support Package. They will not work
in pre-Android 3.0 applications.
After these steps have been performed, it becomes possible to use Fragments in earlier versions of Android. The
Fragment APIs will work the same now in these earlier versions, with the following exceptions:
Change the minimum Android Version – The application no longer needs to target Android 3.0 or
higher, as shown below:
Extend FragmentActivity – The Activities that are hosting Fragments must now inherit from
Android.Support.V4.App.FragmentActivity , and not from Android.App.Activity .
Update Namespaces – Classes that inherit from Android.App.Fragment must now inherit from
Android.Support.V4.App.Fragment . Remove the using statement " using Android.App; " at the top of the
source code file and replace it with " using Android.Support.V4.App ".
Use SupportFragmentManager – Android.Support.V4.App.FragmentActivity exposes a
SupportingFragmentManager property that must be used to get a reference to the FragmentManager . For
example:
With these changes in place, it will be possible to run a Fragment-based application on Android 1.6 or 2.x as well as
on Honeycomb and Ice Cream Sandwich.
Related Links
Android Support Library v4 NuGet
App-Linking in Android
5/2/2018 • 7 minutes to read • Edit Online
This guide will discuss how Android 6.0 supports app -linking, a technique that allows mobile apps to respond to
URLs on websites. It will discuss what app -linking is, how to implement app -linking in an Android 6.0 application,
and how to configure a website to grant permissions to the mobile app for a domain.
Android 6.0 improves on this by using automatic link handling. It is possible for Android to automatically register
an application as the default handler for a URI – the app will automatically launch and navigate directly to the
relevant Activity. How Android 6.0 decides to handle a URI click depends on the following criteria:
1. An existing app is already associated with the URI – The user may have already associated an existing app
with a URI. In that case, Android will continue to use that application.
2. No existing app is associated with the URI, but a supporting app is installed – In this scenario, the user
has not specified an existing app, so Android will use the installed supporting application to handle the request.
3. No existing app is associated with the URI, but many supporting apps are installed – Because there are
multiple applications that support the URI, the disambiguation dialog will be displayed and the user must select
which app will handle the URI.
If the user has no apps installed that support the URI, and one is subsequently installed, then Android will set that
application as the default handler for the URI after verifying the association with the website that is associated with
the URI.
This guide will discuss how to configure an Android 6.0 application and how to create and publish the Digital Asset
Links file to support app-linking in Android 6.0.
Requirements
This guide requires Xamarin.Android 6.1 and an application that targets Android 6.0 (API level 23) or higher.
App-linking is possible in earlier versions of Android by using the Rivets NuGet package from the Xamarin
Component store. The Rivets package is not compatible with app-linking in Android 6.0; it does not support
Android 6.0 app linking.
Android will verify every host that is identified by the intent filters against the Digital Assets File on the website
before registering the application as the default handler for a URI. All the intent filters must pass verification before
Android can establish the app as the default handler.
Creating the Digital Assets Link File
Android 6.0 app-linking requires that Android verify the association between the application and the website
before setting the application as the default handler for the URI. This verification will occur when the application is
first installed. The Digital Assets Links file is a JSON file that is hosted by the relevant webdomain(s).
NOTE
The android:autoVerify attribute must be set by the intent filter – otherwise Android will not perform the verification.
The file is placed by the webmaster of the domain at the location https://domain/.well-known/assetlinks.json.
The Digital Asset File contains the meta-data necessary for Android to verify the association. An assetlinks.json
file has the following key-value pairs:
namespace – the namespace of the Android application.
package_name – the package name of the Android application (declared in the application manifest).
sha256_cert_fingerprints – the SHA256 fingerprints of the signed application. Please see the guide Finding
your Keystore's MD5 or SHA1 Signature for more information on how to obtain the SHA1 fingerprint of an
application.
The following snippet is an example of assetlinks.json with a single application listed:
[
{
"relation":[
"delegate_permission/common.handle_all_urls"
],
"target":{
"namespace":"android_app",
"package_name":"com.example",
"sha256_cert_fingerprints":[
"14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"
]
}
}
]
It is possible to register more than one SHA256 fingerprint to support different versions or builds of your
application. This next assetlinks.json file is an example of registering multiple applications:
[
{
"relation":[
"delegate_permission/common.handle_all_urls"
],
"target":{
"namespace":"android_app",
"package_name":"example.com.puppies.app",
"sha256_cert_fingerprints":[
"14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"
]
}
},
{
"relation":[
"delegate_permission/common.handle_all_urls"
],
"target":{
"namespace":"android_app",
"package_name":"example.com.monkeys.app",
"sha256_cert_fingerprints":[
"14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"
]
}
}
]
The Google Digital Asset Links website has an online tool that may assist with creating and testing the Digital
Assets file.
Testing App-Links
After implementing app-links, the various pieces should be tested to ensure that they work as expected.
It is possible to confirm that the Digital Assets file is properly formatted and hosted by using Google's Digital Asset
Links API, as shown in this example:
https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=
https://<WEB SITE ADDRESS>:&relation=delegate_permission/common.handle_all_urls
There are two tests that can be performed to ensure that the intent filters have been properly configured and that
the app is set as the default handler for a URI:
1. The Digital Asset File is properly hosted as described above. The first test will dispatch an intent which
Android should redirect to the mobile application. The Android application should launch and display the
Activity registered for the URL. At a command prompt type:
2. Display the existing link handling policies for the applications installed on a given device. The following
command will dump a listing of link policies for each user on the device with the following information. At
the command prompt, type the following command:
Summary
This guide discussed how app-linking works in Android 6.0. It then covered how to configure an Android 6.0
application to support and respond to app links. It also discussed how to test app-linking in an Android application.
Related Links
Finding your Keystore's MD5 or SHA1 Signature
Activities and Intents
AppLinks
Google Digital Assets Links
Statement List Generator and Tester
Oreo Features
7/10/2018 • 14 minutes to read • Edit Online
How to get started using Xamarin.Android to develop apps for the latest version of Android.
Android 8.0 Oreo is the latest version of Android available from Google. Android Oreo offers many new features
of interest to Xamarin.Android developers. These features include notification channels, notification badges,
custom fonts in XML, downloadable fonts, autofill, and picture in picture (PIP ). Android Oreo includes new APIs
for these new capabilties, and these APIs are available to Xamarin.Android apps when you use Xamarin.Android
8.0 and later.
This article is structured to help you get started in developing Xamarin.Android apps for Android 8.0 Oreo. It
explains how to install the necessary updates, configure the SDK, and create an emulator (or device) for testing. It
also provides an outline of the new features in Android 8.0 Oreo, with links to sample apps that illustrate how to
use Android Oreo features in Xamarin.Android apps.
Requirements
The following is required to use Android Oreo features in Xamarin-based apps:
Visual Studio – If you are using Windows, version 15.5 or later of Visual Studio is required. If you are
using a Mac, Visual Studio for Mac version 7.2.0 is required.
Xamarin.Android – Xamarin.Android 8.0 or later must be installed and configured with Visual Studio.
Android SDK – Android SDK 8.0 (API 26) or later must be installed via the Android SDK Manager.
Getting Started
To get started using Android Oreo with Xamarin.Android, you must download and install the latest tools and SDK
packages before you can create an Android Oreo project:
1. Update to the latest version of Visual Studio.
2. Install the Android 8.0.0 (API 26) or later packages and tools via the SDK Manager.
3. Create a new Xamarin.Android project that targets Android Oreo (API 26).
4. Configure an emulator or device for testing Android Oreo apps.
Each of these steps is explained in the following sections:
Update Visual Studio and Xamarin.Android
To add Android Oreo support to Visual Studio, do the following:
Visual Studio
Visual Studio for Mac
If you are using Visual Studio 2017:
1. Update to Visual Studio 2017 version 15.7 or later (see Update Visual Studio 2017).
2. Use the SDK Manager to install API level 26.0 or later.
If you are using Visual Studio 2015, we we recommend downgrading SDK Tools to 25 and using the old
Google Emulator manager GUI. SDK tools 25 can still be used alongside API 26, 27, and newer, and won't
impact development for new platforms. This will give you an interface for managing your Android SDK for
older versions of VS.
For more information about Xamarin support for Android Oreo, see the Xamarin.Android 8.0 release notes.
Install the Android SDK
To create a project with Xamarin.Android 8.0, you must first use the Xamarin Android SDK Manager to install the
SDK platform for Android 8.0 - Oreo or later. You must also install Android SDK Tools 26.0 or later.
Visual Studio
Visual Studio for Mac
1. Start the SDK Manager (in Visual Studio, click Tools > Android > Android SDK Manager).
2. Install the Android 8.0 - Oreo packages. If you are using the Android SDK emulator, be sure to include the
x86 system images that you will need:
3. Install Android SDK Tools 26.0.2 or later, Android SDK Platform -Tools 26.0.0 or later, and Android
SDK Build-Tools 26.0.0 (or later):
2. Add the location of the Android SDK bin folder to your PATH . For a typical Xamarin installation, you can
use the following command:
3. Close the Command Prompt window and open a new Command Prompt window. Create a new virtual
device by using the avdmanager command. For example, to create an AVD named AVD -Oreo-8.0 using the
x86 system image for API level 26, use the following command:
4. When you are prompted with Do you wish to create a custom hardware profile [no] you can enter no
and accept the default hardware profile. If you say yes, avdmanager will prompt you with a list of
questions for customizing the hardware profile.
After you avdmanager to create your virtual device, it will be included in the device pull-down menu:
For more information about configuring an Android emulator for testing and debugging, see Debugging on the
Android Emulator.
If you are using a physical device such as a Nexus or a Pixel, you can either update your device through automatic
over the air (OTA) updates or download a system image and flash your device directly. For more information about
manually updating your device to Android Oreo, see Factory Images for Nexus and Pixel Devices.
New Features
Android Oreo introduces a variety of new features and capabilities, such as notification channels, notification
badges, custom fonts in XML, downloadable fonts, autofill, and picture-in-picture. The following sections highlight
these features and provide links to help you get started using them in your app.
Notification Channels
Notification Channels are app-defined categories for notifications. You can create a notification channel for each
type of notification that you need to send, and you can create notification channels to reflect choices made by users
of your app. The new notification channels feature makes it possible for you to give users fine-grained control over
different kinds of notifications. For example, if you are implementing a messaging app, you can create separate
notification channels for each conversation group that is created by a user.
Notification Channels explains how to create a notification channel and use it for posting local notifications. For a
real-world code example, see the NotificationChannels sample; this sample app manages two channels and sets
additional notification options.
Notification Badges
Notification badges are small dots that appear over app icons as shown in this screenshot:
These dots indicate that there are new notifications for one or more notification channels in the app associated
with that app icon – these are notifications that the user has not yet dismissed or acted upon. Users can long-press
on an icon to glance at the notifications associated with a notification badge, dismissing or acting on notifications
from the long-press menu that appeaars.
For more information about notification badges, see the Android Developer Notification Badges topic.
Custom Fonts in XML
Android Oreo introduces Fonts in XML, which makes it possible for you to incorporate custom fonts as resources.
OpenType (.otf) and TrueType (.ttf) font formats are supported. To add fonts as resources, do the following:
1. Create a Resources/font folder.
2. Copy your font files (example, .ttf and .otf files) to Resources/font.
3. If necessary, rename each font file so that it adheres to the Android file naming conventions (i.e., use only
lowercase a -z, 0 -9, and underscores in file names). For example, the font file Pacifico-Regular.ttf could be
renamed to something like pacifico.ttf .
4. Apply the custom font by using the new android:fontFamily attribute in your layout XML. For example, the
following TextView declaration uses the added pacifico.ttf font resource:
<TextView
android:text="Example Text in Pacifico Regular"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/pacifico" />
You can also create a font family XML file that describes multiple fonts as well as style and weight details. For more
information, see the Android Developer Fonts in XML topic.
Downloadable Fonts
Beginning with Android Oreo, apps can request fonts from a provider rather than bundling them into the APK.
Fonts are downloaded from the network only as needed. This feature reduces APK size, conserving phone
memory and cellular data usage. You can also use this feature on Android API versions 14 and higher by installing
the Android Support Libary 26 package.
When your app needs a font, you create a FontsRequest object (specifying the font to download) and then pass it
to a FontsContract method to download the font. The following steps describe the font download process in more
detail:
1. Instantiate a FontRequest object.
2. Subclass and instantiate FontsContract.FontRequestCallback.
3. Implement the FontRequestCallback.OnTypeFaceRetrieved method, which is used to handle completion of
the font request.
4. Implement the FontRequestCallback.OnTypeFaceRequestFailed method, which is used to inform your app
of any errors that take place during the font request process.
5. Call the FontsContract.RequestFonts method to retrieve the font from the font provider.
When you call the RequestFonts method, it first checks to see if the font is locally cached (from a previous call to
RequestFont ). If it is not cached, it calls the font provider, retrieves the font asynchronously, and then passes the
results back to your app by invoking your OnTypeFaceRetrieved method.
The Downloadable Fonts sample demonstrates how to use the Downloadable Fonts feature introduced in Android
Oreo.
For more information about downloading fonts, see the Android Developer Downloadable Fonts topic.
Autofill
The new Autofill framework in Android Oreo makes it easier for users to handle repetitive tasks such as login,
account creation, and credit card transactions. Users spend less time re-typing information (which can lead to input
errors). Before your app can work with the Autofill Framework, an autofill service must be enabled in the system
settings (users can enable or disable autofill).
The AutofillFramework sample demonstrates the use of the Autofill Framework. It includes implementations of
client Activities with views that should be autofilled, and a Service that can provide autofill data to client Activities.
For more information about the new Autofill feature and how to optimize your app for autofill, see the Android
Developer Autofill Framework topic.
Picture in Picture (PIP)
Android Oreo makes it possible for an Activity to launch in picture-in-picture (PIP ) mode, overlaying the screen of
another Activity. This feature is intended for video playback.
To specify that your app's Activity can use PIP mode, set the following flag to true in the Android manifest:
android:supportsPictureInPicture
To specify how your activity should behave when it is in PIP mode, you use the new PictureInPictureParams object.
PictureInPictureParams represents a set of parameters that you use to initialize and update an Activity in PIP
mode (for example, the Activity's preferred aspect ratio). The following new PIP methods were added to Activity
in Android Oreo:
EnterPictureInPictureMode – puts the Activity in PIP mode. The Activity is placed in the corner of the
screen, and the rest of the screen is filled with the previous Activity that was on the screen.
SetPictureInPictureParams – Updates the Activity's PIP configuration settings (for example, a change in
aspect ratio).
The PictureInPicture sample demonstrates basic usage of the Picture-in-Picture (PiP ) mode for handheld devices
introduced in Oreo. The sample plays a video which continues uninterrupted while switching back and forth
between display modes or other activities.
Other Features
Android Oreo contains many other new features such as the Emoji support library, Location API, background
limits, wide-gamut color for apps, new audio codecs, WebView enhancements, improved keyboard navigation
support, and a new AAudio (pro audio) API for high-performance low -latency audio, For more information about
these features, see the Android Developer Android Oreo Features and APIs topic.
Behavior Changes
Android Oreo includes a variety of system and API behavior changes that can have an impact on the functionality
of existing apps. These changes are described as follows.
Background Execution Limits
To improve the user experience, Android Oreo imposes limitations on what apps can do while running in the
background. For example, if the user is watching a video or playing a game, an app running in the background
could impair the performance of a video-intensive app running in the foreground. As a result, Android Oreo places
the following restrictions on apps that are not directly interacting with the user:
1. Background Service Limitations – When an app is running in the background, it has a window of several
minutes in which it is still allowed to create and use services. At the end of that window, Android stops the
app's background service and treats it as being idle.
2. Broadcast Limitations – Android 7.0 (API 25) placed limitations on broadcasts that an app registers to
receive. Android Oreo makes these limitations more stringent. For example, Android Oreo apps can no
longer register broadcast receivers for implicit broadcasts in their manifests.
For more information about the new background execution limits, see the Android Developer Background
Execution Limits topic.
Breaking Changes
Apps that target Android Oreo or higher must modify their apps to support the following changes, where
applicable:
Android Oreo deprecates the ability to set the priority of individual notifications. Instead, you set a
recommended importance level when creating a notification channel. The importance level you assign to a
notification channel applies to all notification messages that you post to it.
For apps targeting Android Oreo, PendingIntent.GetService() does not work due to new limits placed on
services started in the background. If you are targeting Android Oreo, you should use
PendingIntent.GetBroadcast instead.
Sample Code
Several Xamarin.Android samples are available to show you how to take advantage of Android Oreo features:
NotificationsChannels demonstrates how to use the new Notification Channels system introduced in
Android Oreo. This sample manages two notifications channels: one with default importance and the other
with high importance.
PictureInPicture demonstrates basic usage of the Picture-in-Picture (PiP ) mode for handheld devices
introduced in Oreo. The sample plays a video which continues uninterrupted while switching back and forth
between display modes or other activities.
AutofillFramework demonstrates the use of the Autofill Framework. It includes implementations of client
Activities with views that should be autofilled, and a Service that can provide autofill data to client Activities.
Downloadable Fonts provides an example of how to use the Downloadable Fonts feature described earlier.
EmojiCompat demonstrates usage of EmojiCompat support library. You can use this library to prevent your
app from showing missing emoji characters as "tofu" characters.
Location Updates Pending Intent illustrates usage of the Location API to get updates about a device's
location using a PendingIntent .
Location Updates Foreground Service demonstrates how to use the Location API to get updates about a
device's location using a bound and started foreground service.
Video
Android 8.0 Oreo development with C#
Summary
This article introduced Android Oreo and explained how to install and configure the latest tools and packages for
Xamarin.Android development on Android Oreo. It provided an overview of the key features available in Android
Oreo, with links to example source code for several new features. It included links to API documentation and
Android Developer topics to help you get started in creating apps for Android Oreo. It also highlighted the most
important Android Oreo behavior changes that could impact existing apps.
Related Links
Android 8.0 Oreo
Nougat Features
7/25/2018 • 10 minutes to read • Edit Online
How to get started using Xamarin.Android to develop apps for Android Nougat.
This article provides an outline of the features introduced in Android Nougat, explains how to prepare
Xamarin.Android for Android Nougat development, and provides links to sample applications that illustrate how to
use Android Nougat features in Xamarin.Android apps.
Overview
Android Nougat is Google's followup to Android 6.0 Marshmallow. Xamarin.Android provides support for
Android 7.x Bindings in Xamarin Android 7.0 and later. Android Nougat adds many new APIs for the Nougat
features described below; these APIs are available to Xamarin.Android apps when you use Xamarin.Android 7.0.
For more information about Android 7.x APIs, see Android 7.1 for Developers. For a list of known
Xamarin.Android 7.0 issues, please see the release notes.
Android Nougat provides many new features of interest to Xamarin.Android developers. These features include:
Multi-window support – This enhancement makes it possible for users to open two apps on the screen at
once.
Notification Enhancements – The redesigned notifications system in Android Nougat includes a Direct
Reply feature that allow users to quickly respond to text messages directly from the notification UI. Also, if
your app creates notifications for received messages, the new bundled notifications feature can bundle
notifications together as a single group when more than one message is received.
Data Saver – This feature is a new system service that helps reduce cellular data use by apps; it gives users
control over how apps use cellular data.
In addition, Android Nougat brings many other enhancements of interest to app developers such as a new
network security configuration feature, Doze on the Go, key attestation, new Quick Settings APIs, multi-locale
support, ICU4J APIs, WebView enhancements, access to Java 8 language features, scoped directory access, a
custom pointer API, platform VR support, virtual files, and background processing optimizations.
This article explains how to get started building apps with Android Nougat to try out the new features and plan
migration or feature work to target the new Android Nougat platform.
Requirements
The following is required to use the new Android Nougat features in Xamarin-based apps:
Visual Studio or Visual Studio for Mac – If you are using Visual Studio, version 4.2.0.628 or later of
Visual Studio Tools for Xamarin is required. If you are using Visual Studio for Mac, version 6.1.0 or later of
Visual Studio for Mac is required.
Xamarin.Android – Xamarin.Android 7.0 or later must be installed and configured with either Visual
Studio or Visual Studio for Mac.
Android SDK - Android SDK 7.0 (API 24) or later must be installed via the Android SDK Manager.
Java Developer Kit – Xamarin Android 7.0 development requires JDK 8 or later if you are developing for
API level 24 or greater (JDK 8 also supports API levels earlier than 24). The 64-bit version of JDK 8 is
required if you are using custom controls or the Forms Previewer.
IMPORTANT
Xamarin.Android does not support JDK 9.
Note that apps must be rebuilt with Xamarin C6SR4 or later to work reliably with Android Nougat. Because
Android Nougat can link only to NDK-provided native libraries, existing apps using libraries such as
Mono.Data.Sqlite.dll may crash when running on Android Nougat if they are not properly rebuilt.
Getting Started
To get started using Android Nougat with Xamarin.Android, you must download and install the latest tools and
SDK packages before you can create an Android Nougat project:
1. Install the latest Xamarin.Android updates from the Xamarin.
2. Install the Android 7.0 (API 24) packages and tools or later.
3. Create a new Xamarin.Android project that targets Android Nougat.
4. Configure an emulator or device for Android Nougat.
Each of these steps is explained in the following sections:
Install Xamarin Updates
To add Xamarin support for Android Nougat, change the updates channel in Visual Studio or Visual Studio for
Mac to the Stable channel and apply the latest updates. If you also need features that are currently available only in
the Alpha or Beta channel, you can switch to the Alpha or Beta channel (the Alpha and Beta channels also provide
support for Android 7.x). For information about how to change the updates (releases) channel, see Changing the
Updates Channel.
Install the Android SDK
To create a project with Xamarin Android 7.0, you must first use the Android SDK Manager to install SDK
Platform Android N (API 24) or later. You must also install the latest Android SDK Tools:
1. Start the Android SDK Manager (in Visual Studio for Mac, use Tools > Open Android SDK Manager…; in
Visual Studio, use Tools > Android > Android SDK Manager).
2. Install Android 7.0 (API 24) or later:
3. Install the latest Android SDK tools:
You must install Android SDK Tools revision 25.2.2 or later, Android SDK Platform tools 24.0.3 or later, and
Android SDK Build tools 24.0.2 or later.
4. Verify that the Java Development Kit Location is configured for JDK 1.8:
To view this setting in Visual Studio, click Tools > Options > Xamarin > Android Settings. In Visual
Studio for Mac, click Preferences > Projects > SDK Locations > Android.
Start a Xamarin.Android Project
Create a new Xamarin.Android project. If you are new to Android development with Xamarin, see Hello, Android
to learn about creating Xamarin.Android projects.
When you create an Android project, you must configure the version settings to target Android 7.0 or later. For
example, to target your project for Android 7.0, you must configure the target Android API level of your project to
Android 7.0 (API 24 - Nougat). It is recommended that you set your target framework level to API 24 or later.
For more about configuring Android API level levels, see Understanding Android API Levels.
NOTE
Currently you must set the Minimum Android version to Android 7.0 (API 24 - Nougat) to deploy your app to Android
Nougat devices or emulators.
If you are using a physical device such as a Nexus 5X, 6, or 9, you can either update your device through automatic
over the air (OTA) updates or download a system image and flash your device directly. For more information about
manually updating your device to Android Nougat, see OTA Images for Nexus Devices.
Note that Nexus 5 devices are not supported by Android Nougat.
New Features
Android Nougat introduces a variety of new features and capabilities, such as Multi-window Support, Notifications
enhancements, and Data Saver. The following sections highlight these features and provide links to help you get
started using them in your app.
Multi-Window Mode
Multi-window mode makes it possible for users to open two apps at once with full multitasking support. These
apps can run side-by-side (landscape) or one-above-the-other (portrait) in split-screen mode. Users can drag a
divider between the apps to resize them, and they can cut and paste content the between apps. When two apps are
presented in multi-window mode, the selected activity continues to run while the unselected activity is paused but
still visible. Multi-window mode does not modify the Android activity lifecycle.
You can configure how the activities of your Xamarin.Android app support multi-window mode. For example, you
can configure attributes that set the minimum size and the default height and width of your app in multi-window
mode. You can use the new Activity.IsInMultiWindowMode property to determine if your activity is in multi-window
mode. For example:
if (!IsInMultiWindowMode) {
multiDisabledMessage.Visibility = ViewStates.Visible;
} else {
multiDisabledMessage.Visibility = ViewStates.Gone;
}
The MultiWindowPlayground sample app includes C# code that demonstrates how to take advantage of multiple
window user interfaces with your app.
For more information about multi-window mode, see the Multi-Window Support.
Enhanced Notifications
Android Nougat introduces a redesigned notification system. It features a new Direct Reply feature that makes it
possible for users to quickly reply to notifications for incoming text messages directly in the notification UI.
Starting with Android 7.0, notification messages can be bundled together as a single group when more than one
message is received. Also, developers can customize notification views, leverage system decorations in
notifications, and take advantage of new notification templates when generating notifications.
Direct Reply
When a user receives a notification for incoming message, Android Nougat makes it possible to reply to the
message within the notification (rather than open up the messaging app to send a reply). This inline reply feature
makes it possible for users to quickly respond to an SMS or text message directly within the notification interface:
To support this feature in your app, you must add inline reply actions to your app via a RemoteInput object so that
users can reply via text directly from the notification UI. For example, the following code builds a RemoteInput for
receiving text input, builds a pending intent for the reply action, and creates a remote input enabled action:
The Messaging Service sample app includes C# code that demonstrates how to extend notifications with a
RemoteInput object. For more information about adding inline reply actions to your app for Android 7.0 or later,
see the Android Replying to Notifications topic.
Bundled Notifications
Android Nougat can group notification messages together (for example, by message topic) and display the group
rather than each separate message. This bundled notifications feature makes it possible for users to dismiss or
archive a group of notifications in one action. The user can slide down to expand the bundle of notifications to view
each notification in detail:
To support bundled notifications, your app can use the Builder.SetGroup method to bundle similar notifications.
For more information about bundled notification groups in Android N, see the Android Bundling Notifications
topic.
Custom Views
Android Nougat makes it possible for you to create custom notification views with system notification headers,
actions, and expandable layouts. For more information about custom notification views in Android Nougat, see the
Android Notification Enhancements topic.
Data Saver
Beginning with Android Nougat, users can enable a new Data Saver setting that blocks background data usage.
This setting also signals your app to use less data in the foreground wherever possible. The ConnectivityManager
has been extended in Android Nougat so that your app can check whether the user has enabled Data Saver so that
your app can make an effort to limit its data usage when Data Saver is enabled.
For more information about the new Data Saver feature in Android Nougat, see the Android Optimizing Network
Data Usage topic.
App Shortcuts
Android 7.1 introduced an App Shortcuts feature that makes it possible for users to quickly start common or
recommended tasks with your app. To activate the menu of shortcuts, the user long-presses the app icon for a
second or more – the menu appears with a quick vibration. Releasing the press causes the menu to remain:
This feature is available only API level 25 or higher. For more information about the new App Shortcuts feature in
Android 7.1, see the Android App Shortcuts topic.
Sample Code
Several Xamarin.Android samples are available to show you how to take advantage of Android Nougat features:
MultiWindowPlayground demonstrates the use of the multi-window API available in Android Nougat. You
can switch the sample app into multi-windows mode to see how it affects the app's lifecycle and behavior.
Messaging Service is a simple service that sends notifications using the NotificationCompatManager . It also
extends the notification with a RemoteInput object to allow Android Nougat devices to reply via text directly
from the notification without having to open an app.
Active Notifications demonstrates how to use the NotificationManager API to tell you how many
notifications your application is currently displaying.
Scoped Directory Access Demonstrates how to use the scoped directory access API to easily access specific
directories. This serves as an alternative to having to define READ_EXTERNAL_STORAGE or
WRITE_EXTERNAL_STORAGE permissions in your manifest.
Direct Boot Illustrates how to store data in a device-encrypted storage which is always available while the
device is booted both before and after any user credentials(PIN/Pattern/Password) are entered.
Summary
This article introduced Android Nougat and explained how to install and configure the latest tools and packages
for Xamarin.Android development on Android Nougat. It also provided an overview of the key features available
in Android Nougat, with links to example source code to help you get started in creating apps for Android Nougat.
Related Links
Android 7.1 For Developers
Xamarin Android 7.0 Release Notes
Marshmallow Features
7/25/2018 • 11 minutes to read • Edit Online
This article helps you get started using in using Xamarin.Android to develop apps for Android 6.0 Marshmallow.
This article provides an outline of the new features in Android 6.0 Marshmallow, explains how to prepare
Xamarin.Android for Android Marshmallow development, and provides links to sample applications that illustrate
how to make use of new Android Marshmallow features in Xamarin.Android apps.
Overview
Android 6.0 Marshmallow, is the next major Android release after Android Lollipop. Xamarin.Android supports
Android Marshmallow and includes:
API 23/Android 6.0 Bindings – Android 6.0 adds many new APIs for the new features described below; these
APIs are available to Xamarin.Android apps when you target API Level 23. For more information about
Android 6.0 APIs, see Android 6.0 APIs.
Although the Marshmallow release is mainly focused on "polish and quality", it also provides many new features of
interest to Xamarin.Android developers. These features include:
Runtime Permissions – This enhancement makes it possible for users to approve security permissions on
a case-by-case basis at run time.
Authentication Improvements – Starting with Android Marshmallow, apps can now use fingerprint
sensors to authenticate users, and a new confirm credential feature minimizes the need for entering
passwords.
App Linking – This feature helps to eliminate the necessity of having the App Chooser pop up by
automatically associating apps with web domains.
Direct Share – You can define direct share targets that make sharing quick and intuitive for users; this
feature allows uers to share content with other apps.
Voice Interactions – This new API allows you to build conversational voice features into your app.
4K Display Mode – In Android Marshmallow, your app can request a 4K display resolution on hardware
that supports it.
New Audio Features – Starting with Marshmallow, Android now supports the MIDI protocol. It also
provides new classes to create digital audio capture and playback objects, and it offers new API hooks for
associating audio and input devices.
New Video Features – Marshmallow provides a new class that helps apps render audio and video streams
in sync; this class also provides support for dynamic playback rate.
Android for Work – Marshmallow includes enhanced controls for corporate-owned, single-user devices. It
supports silent install and uninstall of apps by the device owner, auto-acceptance of system updates,
improved certificate management, data usage tracking, permissions management, and work status
notifications.
Material Design Support Library – The new Design Support Library provides design components and
patterns that makes it easier for you to build Material Design look and feel into your app.
In addition, many core Android library updates were released with Android M, and these updates provide new
features for both Android M and earlier versions of Android.
In addition, many core Android library updates were released with Android Marshmallow, and these updates
provide new features for both Android Marshmallow and earlier versions of Android. This article explains how to
get started building apps with Android Marshmallow, and it provides an overview of the new feature highlights in
Android 6.0.
Requirements
The following is required to use the new Android Marshmallow features in Xamarin-based apps:
Xamarin.Android – Xamarin.Android 5.1.7.12 or later must be installed and configured with either Visual
Studio or Xamarin Studio.
Visual Studio for Mac or Visual Studio – If you are using Visual Studio for Mac, version 5.9.7.22 or later
is required. If you are using Visual Studio, version 3.11.1537 or later of the Xamarin tools for Visual Studio
is required.
Android SDK – Android SDK 6.0 (API 23) or later must be installed via the Android SDK Manager.
Java Developer Kit – Xamarin.Android requires JDK 1.8 or later if you are developing for API level 24 or
greater (JDK 1.8 also supports API levels earlier than 24, including Marshmallow ). The 64-bit version of
JDK 1.8 is required if you are using custom controls or the Forms Previewer.
You can continue to use JDK 1.7 if you are developing specifically for API level 23 or earlier.
Getting Started
To get started using Android Marshmallow with Xamarin.Android, you must download and install the latest tools
and SDK packages before you can create an Android Marshmallow project:
1. Install the latest Xamarin updates from the Stable channel.
2. Install the Android 6.0 Marshmallow SDK packages and tools.
3. Create a new Xamarin.Android project that targets Android 6.0 Marshmallow (API Level 23).
4. Configure an emulator or device for Android Marshmallow.
Each of these steps is explained in the following sections:
Install Xamarin Updates
To update Xamarin so that it includes support for Android 6.0 Marshmallow, change the update channel to Stable
and install all updates. For more information about installing updates from the updates channel, see Change the
Updates Channel.
Install the Android 6.0 SDK
To create a Xamarin.Android project for Android Marshmallow, you must first use the Android SDK Manager to
install the Android 6.0 SDK:
Start the Android SDK Manager (in Visual Studio for Mac, use Tools > SDK Manager; in Visual Studio, use
Tools > Android > Android SDK Manager) and install the latest Android SDK Tools:
You must install Android SDK Tools revision 24.3.4 or later. For more information about using the Android SDK
Manager to install the Android 6.0 SDK, see SDK Manager.
Start a Xamarin.Android Project
Create a new Xamarin.Android project. If you are new to Android development with Xamarin, see Hello, Android
to learn about creating Android projects.
When you create an Android project, you must configure the version settings to target Android 6.0 MarshMallow.
To target your project for Marshmallow, you must configure your project for API level 23 (Xamarin.Android
v6.0 Support). For more about configuring Android API level levels, see Understanding Android API Levels.
Configure an Emulator or Device
If you are using an emulator, start the Android AVD Manager and create a new device using the following settings:
Device: Nexus 5, 6, or 9.
Target: Android 6.0 - API Level 23
ABI: x86
For example, this virtual device is configured to emulate a Nexus 5:
If you are using a physical device such as a Nexus 5, 6, or 9, you can install a preview image of Android
Marshmallow. For more information about updating your device to Android Marshmallow, see Hardware System
Images.
New Features
Many of the changes introduced in Android Marshmallow are focused on improving the Android user experience,
increasing performance, and fixing bugs. However, Marshmallow also introduced some extensive changes to the
fundamentals of the Android platform. The following sections highlight these enhancements and provide links to
help you get started in using the new Android Marshmallow features in your app.
Runtime Permissions
The Android Permissions system has been significantly optimized and simplified since Android Lollipop. In
Android Marshmallow, users grant permissions on a case-by-case basis at runtime rather than at install time. To
support this feature on Android Marshmallow and later, you design your app to prompt the user for permissions at
runtime (in the context of where the permissions are needed). This change makes it easier for users to start using
your app immediately because it streamlines the process of installing and upgrading your app.
See Requesting Runtime Permissions in Android Marshmallow for more details (including code examples) about
implementing Runtime Permissions in Xamarin.Android apps. Xamarin also provides a sample app that illustrates
how runtime permissions work in Android Marshmallow (and later): RuntimePermissions.
This sample app demonstrates the following:
How to check and request permissions at run time.
How to declare permissions for Android M devices.
To use this sample app:
1. Tap the Camera or Contacts buttons to display a permissions request dialog.
2. Grant permission to view Camera or Contacts fragments.
For more information about the new runtime permissions features in Android Marshmallow, see Working with
System Permissions.
Authentication Enhancements
Android Marshmallow includes two authentication enhancements that help eliminate the need for passwords:
Fingerprint Authentication – Uses a fingerprint scan to authenticate users.
Confirm Credential – Authenticates users based on how long the device has been unlocked.
The links and sample apps described next can help you become familiar with these new features.
Fingerprint Authentication
On devices that support fingerprint scanning hardware, you can use the new FingerPrintManager class to
authenticate a user. For more information about the fingerprint authentication feature in Android Marshmallow,
see Fingerprint Authentication.
Xamarin provides a sample app that illustrates how to use registered fingerprints to authenticate a user in your
app: FingerprintDialog.
To use this sample app:
1. Touch the Purchase button to open a fingerprint authentication dialog.
2. Scan in your registered fingerprint to authenticate.
Note that this sample app requires a device with a fingerprint reader. This app does not store your fingerprint (or
your password).
Voice Interactions
The new Voice Interactions feature introduced in Android Marshmallow allows users of your app to use their voice
to confirm actions and select from a list of options. For more information about Voice Interactions, see Overview
of the Voice Interaction API.
See Add a Conversation to your Android App with Voice Interactions for more details (including code examples)
about implementing Voice Interactions in Xamarin.Android apps. A sample app is available that illustrates how to
use the Voice Interaction API in a Xamarin.Android app: Voice Interactions.
Confirm Credential
Using the new confirm credential feature of Android Marshmallow, you can free users from having to remember
and enter app-specific passwords by authenticating them based on how long their device has been unlocked. To do
this, you use the new SetUserAuthenticationValidityDurationSeconds method of the KeyGenerator . Use the
KeyGuardManager 's CreateConfirmDeviceCredentialIntent method to re-authenticate the user from within your app.
For more information about this new feature in Android Marshmallow, see Confirm Credential.
Xamarin provides a sample app that illustrates how to use device credentials (such as PIN, pattern, or password) in
your app: ConfirmCredential
To use this sample app:
1. Setup a secure lock screen on your device (Secure > Security > Screenlock).
2. Tap the Purchase button and confirm the secure lock screen credentials.
Chrome Custom Tabs
App developers face a choice when a user taps a URL: the app can either launch a browser or use an in-app
browser based on a WebView . Both options present challenges – launching the browser is a heavy context switch
that isn't customizable, while WebView s do not share state with the browser. Also, use of WebView s can add extra
maintenance overhead.
Chrome Custom Tabs makes it possible for you to easily and elegantly display websites with the power of Chrome
without having your users leave your app. This feature gives your app more control over the user's web experience;
it make transitions between native and web content more seamless without having to resort to a WebView . Your
app can also affect how Chrome looks and feels by customizing the following:
Toolbar color
Enter and exit animations
Custom actions in the Chrome toolbar and overflow menu
Chrome pre-start and content pre-fetch (for faster loading)
To take advantage of this feature in your Xamarin.Android app, download and install the Android Support Custom
Tabs Library. For more information about this feature, see Chrome Custom Tabs.
Material Design Support Library
Android Lollipop introduced Material Design as a new design language to refresh the Android experience (see
Material Theme for information about using material design in Xamarin.Android apps). With Android
Marshmallow, Google introduced the Android Design Support Library to make it easier for app developers to
adopt material design look and feel. This library includes the following components:
CoordinatorLayout – The new CoordinatorLayout widget is similar to but more powerful than a
FrameLayout . You can use CoordinatorLayout as a container for child views or as a top-level layout, and it
provides a layout_anchor attribute that can be used to anchor views relative to other views.
Collapsing Toolbars – The new CollapsingToolbarLayout is a collapsing app bar that is a wrapper for
Toolbar . ( Note that the app bar is what was formerly referred to as the action bar.)
Floating Action Button – A round button that denotes the primary action on your app's interface.
Floating Labels for Editing Text – Uses a new TextInputLayout widget (which wraps EditText ) to show
a floating label when a hint is hidden when a user inputs text.
Navigation View – The new NavigationView widget helps you use the navigation drawer in a way that is
easier for users to navigate.
Snackbar – The new SnackBar widget is a lightweight feedback mechanism (similar to a toast) that displays
a brief message at the bottom of the screen, appearing above all other elements on the screen.
Material Tabs – The new TabLayout widget provides a horizontal layout for displaying tabs as way to
implement top-level navigation in your app.
To take advantage of the Design Support Library in your Xamarin.Android app, download and install the Xamarin
Xamarin Support Library Design NuGet package.
See Beautiful Material Design with the Android Support Design Library for more details (including code
examples) about using the Material Design Support Library in Xamarin.Android apps. Xamarin provides a sample
app that demos the new Android Design library on Xamarin.Android – Cheesesquare. This sample demonstrates
the following features of the Design library:
Collapsing toolbar
Floating action button
View anchoring
NavigationView
Snackbar
For more information about the Design library, see Android Design Support Library in the Android Developer's
blog.
Additional Library Updates
In addition to Android Marshmallow, Google has announced related updates to several core Android libraries.
Xamarin provides Xamarin.Android support for these updates through several preview -release NuGet packages:
Google Play Services – The latest version of Google Play Services includes the new App Invites feature,
which makes it possible for users to share their app with friends. For more information about this feature,
see Expand Your App's Reach with Google's App Invites.
Android Support Libraries – These NuGets offer features that are only available for library APIs while
providing backward-compatible versions of the Android framework APIs.
Android Wearable Library – this NuGet includes Google Play Services bindings. The latest version of the
wearable library brings new features (including easier navigation for custom apps) to the Android Wear
platform.
Summary
This article introduced Android Marshmallow and explained how to install and configure the latest tools and
packages for Xamarin.Android development on Marshmallow. It also provided an overview of the most exciting
new Android Marshmallow features for Xamarin.Android development.
Related Links
Android 6.0 Marshmallow
Get the Android SDK
Feature Overview
Release Notes
RuntimePermissions (sample)
ConfirmCredential (sample)
FingerprintDialog (sample)
Lollipop Features
4/12/2018 • 21 minutes to read • Edit Online
This article provides a high level overview of the new features introduced in Android 5.0 (Lollipop ). These features
include a new user interface style called Material Theme, as well as new supporting features such as animations,
view shadows, and drawable tinting. Android 5.0 also includes enhanced notifications, two new UI widgets, a new
job scheduler, and a handful of new APIs to improve storage, networking, connectivity, and multimedia
capabilities.
Lollipop Overview
Android 5.0 (Lollipop) introduces a new design language, Material Design, and with it a supporting cast of new
features to make apps easier and more intuitive to use. With Material Design, Android 5.0 not only gives Android
phones a facelift; it also provides a new set of design rules for Android-based tablets, desktop computers,
watches, and smart TVs. These design rules emphasize simplicity and minimalism while making use of familiar
tactile attributes (such as realistic surface and edge cues) to help users quickly and intuitively understand the
interface.
Material Theme is the embodiment of these UI design principles in Android. This article begins by covering
Material Theme's supporting features:
Animations – Touch feedback animations, activity transition animations, view state transition animations,
and a reveal effect.
View shadows and elevation – Views now have an elevation property; views with higher elevation
values cast larger shadows on the background.
Color features – Drawable tinting makes it possible for you to reuse image assets by changing their color,
and prominent color extraction helps you dynamically theme your app based on colors in an image.
Many Material Theme features are already built into the Android 5.0 UI experience, while others must be
explicitly added to apps. For example, some standard views (such as buttons) already include touch feedback
animations, while apps must enable most view shadows.
In addition to the UI improvements brought about through Material Theme, Android 5.0 also includes several
other new features that are covered in this article:
Enhanced notifications – Notifications in Android 5.0 have been significantly updated with a new look,
support for lockscreen notifications, and a new Heads-up notification presentation format.
New UI widgets – The new RecyclerView widget makes it easier for apps to convey large data sets and
complex information, and the new CardView widget provides a simplified card-like presentation format for
displaying text and images.
New APIs – Android 5.0 adds new APIs for multiple network support, improved Bluetooth connectivity,
easier storage management, and more flexible control of multimedia players and camera devices. A new
job scheduling feature is available to run tasks asynchronously at scheduled times. This feature helps to
improve battery life by, for example, scheduling tasks to take place when the device is plugged in and
charging.
Requirements
The following is required to use the new Android 5.0 features in Xamarin-based apps:
Xamarin.Android – Xamarin.Android 4.20 or later must be installed and configured with either Visual
Studio or Visual Studio for Mac.
Android SDK – Android 5.0 (API 21) or later must be installed via the Android SDK Manager.
Java Developer Kit – Xamarin.Android requires JDK 1.8 or later if you are developing for API level 24 or
greater (JDK 1.8 also supports API levels earlier than 24, including Lollipop). The 64-bit version of JDK 1.8
is required if you are using custom controls or the Forms Previewer.
You can continue to use JDK 1.7 if you are developing specifically for API level 23 or earlier.
Also, install the latest Android 5.0 SDK packages (API 21 or later):
For more information about using the Android SDK Manager, see SDK Manager.
4. Create a new Xamarin.Android project. If you are new to Android development with Xamarin, see Hello,
Android to learn about creating Android projects. When you create an Android project, be sure to
configure the version settings for Android 5.0. In Visual Studio for Mac, navigate to Project Options >
Build > General and set Target framework to Android 5.0 (Lollipop) or later:
Under Project Options > Build > Android Application, set minimum and target Android version to
Automatic - use target framework version:
5. Configure an emulator or an Android device to test your app. If you are using an emulator, see Android
Emulator Setup to learn how to configure an Android emulator for use with Xamarin Studio or Visual
Studio. If you are using an Android device, see Setting Up the Preview SDK to learn how to update your
device for Android 5.0. To configure your Android device for running and debugging Xamarin.Android
applications, see Set Up Device for Development.
Note: If you are updating an existing Android project that was targeting the Android L Preview, you must update
the Target Framework and Android version to the values described above.
Important Changes
Previously published Android apps could be affected by changes in Android 5.0. In particular, Android 5.0 uses a
new runtime and a significantly changed notification format.
Android Runtime
Android 5.0 uses the new Android Runtime (ART) as the default runtime instead of Dalvik. ART implements
several major new features:
Ahead-of-time (AOT) compilation – AOT can improve app performance by compiling app code before
the app is first launched. When an app is installed, ART generates a compiled app executable for the target
device.
Improved garbage collection (GC ) – GC improvements in ART can also improve app performance.
Garbage collection now uses one GC pause instead of two, and concurrent GC operations complete in a
more timely fashion.
Improved app debugging – ART provides more diagnostic detail to help in analyzing exceptions and
crash reports.
Existing apps should work without change under ART – except for apps that exploit techniques unique to the
previous Dalvik runtime, which may not work under ART. For more information about these changes, see
Verifying App Behavior on the Android Runtime (ART).
Notification Changes
Notifications have changed significantly in Android 5.0:
Sounds and vibration are handled differently – Notification sounds and vibrations are now handled
by Notification.Builder instead of Ringtone , MediaPlayer , and Vibrator .
New color scheme – In accordance with Material Theme, notifications are rendered with dark text over
white or very light backgrounds. Also, alpha channels in notification icons may be modified by Android to
coordinate with system color schemes.
Lockscreen notifications – Notifications can now appear on the device lockscreen.
Heads-up – High-priority notifications now appear in a small floating window (Heads-up notification)
when the device is unlocked and the screen is turned on.
In most cases, porting existing app notification functionality to Android 5.0 requires the following steps:
1. Convert your code to use Notification.Builder (or NotificationsCompat.Builder ) for creating
notifications.
2. Verify that your existing notification assets are viewable in the new Material Theme color scheme.
3. Decide what visibility your notifications should have when they are presented on the lockscreen. If a
notification is not public, what content should show up on the lockscreen?
4. Set the category of your notifications so they are handled correctly in the new Android 5.0 Do not disturb
mode.
If your notifications present transport controls, display media playback status, use RemoteControlClient , or call
ActivityManager.GetRecentTasks , see Important Behavior Changes for more information about updating your
notifications for Android 5.0.
For information about creating notifications in Android, see Local Notifications. The Compatibility section of this
article explains how to create notifications that are downward-compatible with earlier versions of Android.
Material Theme
The new Android 5.0 Material Theme brings sweeping changes to the look and feel of the Android UI. Visual
elements now use tactile surfaces that take on the bold graphics, typography, and bright colors of print-based
design. Examples of Material Theme are depicted in the following screenshots:
Android 5.0 greets you with the home screen shown on the left. The center screenshot is the first screen of the
app list, and the screenshot on the right is the Settings screen. Google's Material Design specification explains
the underlying design rules behind the new Material Theme concept.
Material Theme includes three built-in flavors that you can use in your app: the Theme.Material dark theme (the
default), the Theme.Material.Light theme, and the Theme.Material.Light.DarkActionBar theme:
For more about using Material Theme features in Xamarin.Android apps, see Material Theme.
Animations
Android 5.0 provides touch feedback animations, activity transition animations, and view state transition
animations to make app interfaces more intuitive to use. Also, Android 5.0 apps can use reveal effect animations
to hide or reveal views. You can use curved motion settings to configure how quickly or slowly animations are
rendered.
Touch Feedback Animations
Touch feedback animations provide users with visual feedback when a view has been touched. For example,
buttons now display a ripple effect when they are touched – this is the default touch feedback animation in
Android 5.0. Ripple animation is implemented by the new RippleDrawable class. The ripple effect can be
configured to end at the bounds of the view or extend beyond the bounds of the view. For example, the following
sequence of screenshots illustrates the ripple effect in a button during touch animation:
Initial touch contact with the button occurs in the first image on the left, while the remaining sequence (from left
to right) illustrates how the ripple effect spreads out to the edge of the button. When the ripple animation ends,
the view returns to its original appearance. The default ripple animation takes place in a fraction of a second, but
the length of the animation can be customized for longer or shorter lengths of time.
For more on touch feedback animations in Android 5.0, see Customize Touch Feedback.
Activity Transition Animations
Activity transition animations give users a sense of visual continuity when one activity transitions to another. Apps
can specify three types of transition animations:
Enter transition – For when an activity enters the scene.
Exit transition – For when an activity exits the scene.
Shared element transition – For when a view that is common to two activities changes as the first
activity transitions to the next.
For example, the following sequence of screenshots illustrates a shared element transition:
A shared element (a photo of a caterpillar) is one of several views in the first activity; it enlarges to become the
only view in the second activity as the first activity transitions to the second.
Enter Transition Animation Types
For enter transitions, Android 5.0 provides three types of animations:
Explode animation – Enlarges a view from the center of the scene.
Slide animation – Moves a view in from one of the edges of a scene.
Fade animation – Fades a view into the scene.
Exit Transition Animation Types
For exit transitions, Android 5.0 provides three types of animations:
Explode animation – Shrinks a view to the center of the scene.
Slide animation – Moves a view out to one of the edges of a scene.
Fade animation – Fades a view out of the scene.
Shared Element Transition Animation Types
Shared element transitions support multiple types of animations, such as:
Changing the layout or clip bounds of a view.
Changing the scale and rotation of a view.
Changing the size and scale type for a view.
For more about activity transition animations in Android 5.0, see Customize Activity Transitions.
View State Transition Animations
Android 5.0 makes it possible for animations to run when the state of a view changes. You can animate view state
transitions by using one of the following techniques:
Create drawables that animate state changes associated with a particular view. The new
AnimatedStateListDrawable class lets you create drawables that display animations between view state
changes.
Define animation functionality that runs when the state of a view changes. The new StateListAnimator
class lets you define an animator that runs when the state of a view changes.
For more about view state transition animations in Android 5.0, see Animate View State Changes.
Reveal Effect
The reveal effect is a clipping circle that changes radius to reveal or hide a view. You can control this effect by
setting the initial and final radius of the clipping circle. The following sequence of screenshots illustrates a reveal
effect animation from the center of the screen:
The next sequence illustrates a reveal effect animation that takes place from the bottom left corner of the screen:
Reveal animations can be reversed; that is, the clipping circle can shrink to hide the view rather than enlarge to
reveal the view.
For more information on the Android 5.0 reveal effect in, see Use the Reveal Effect.
Curved Motion
In addition to these animation features, Android 5.0 also provides new APIs that enable you to specify the time
and motion curves of animations. Android 5.0 uses these curves to interpolate temporal and spatial movement
during animations. Three curves are defined in Android 5.0:
Fast_out_linear_in – Accelerates quickly and continues to accelerate until the end of the animation.
Fast_out_slow_in – Accelerates quickly and slowly decelerates towards the end of the animation.
Linear_out_slow_in – Begins with a peak velocity and slowly decelerates to the end of the animation.
You can use the new PathInterpolator class to specify how motion interpolation takes place. PathInterpolator is
an interpolator that traverses animation paths according to specified control points and motion curves. For more
information about how to specify curved motion settings in Android 5.0, see Use Curved Motion.
View Shadows & Elevation
In Android 5.0, you can specify the elevation of a view by setting a new Z property. A greater Z value causes
the view to cast a larger shadow on the background, making the view appear to float higher above the
background. You can set the initial elevation of a view by configuring its elevation attribute in the layout.
The following example illustrates the shadows cast by an empty TextView control when its elevation attribute is
set to 2dp, 4dp, and 6dp, respectively:
View shadow settings can be static (as shown above) or they can be used in animations to make a view appear to
temporarily rise above the view's background. You can use the ViewPropertyAnimator class to animate the
elevation of a view. The elevation of a view is the sum of its layout elevation setting plus a translationZ
property that you can set through a ViewPropertyAnimator method call.
For more about view shadows in Android 5.0, see Defining Shadows and Clipping Views.
Color Features
Android 5.0 provides two new features for managing color in apps:
Drawable tinting lets you alter the colors of image assets by changing a layout attribute.
Prominent color extraction makes it possible for you to dynamically customize your app's color theme to
coordinate with the color palette of a displayed image.
Drawable Tinting
Android 5.0 layouts recognize a new tint attribute that you can use to set the color of drawables without having
to create multiple versions of these assets to display different colors. To use this feature, you define a bitmap as an
alpha mask and use the tint attribute to define the color of the asset. This makes it possible for you to create
assets once and color them in your layout to match your theme.
In the following example, a single image asset – a white logo with a transparent background – is used to create
tint variations:
This logo is displayed above a blue circular background as shown in the following examples. The image on the
left is how the logo appears without a tint setting. In the center image, the logo's tint attribute is set to a dark
gray. In the image on the right, tint is set to a light gray:
For more about drawable tinting in Android 5.0, see Drawable Tinting.
Prominent Color Extraction
The new Android 5.0 Palette class lets you extract colors from an image so that you can dynamically apply them
to a custom color palette. The Palette class extracts six colors from an image and labels these colors according
to their relative levels of color saturation and brightness:
Vibrant
Vibrant dark
Vibrant light
Muted
Muted dark
Muted light
For example, in the following screenshots, a photo viewing app extracts the prominent colors from the image on
display and uses these colors to adapt the color scheme of the app to match the image:
In the above screenshots, the action bar is set to the extracted "vibrant light" color and the background is set to
the extracted "vibrant dark" color. In each example above, a row of small color squares is included to illustrate the
palette colors that were extracted from the image.
For more about color extraction in Android 5.0, see Extracting Prominent Colors from an Image.
New UI Widgets
Android 5.0 introduces two new UI widgets:
RecyclerView – A view group that displays a list of scrollable items.
CardView – A basic layout with rounded corners.
Both widgets include baked-in support for Material Theme features; for example, RecyclerView uses animations
for adding and removing views, and CardView uses view shadows to make each card appear to float above the
background. Examples of these new widgets are shown in the following screenshots:
The screenshot on the left is an example of RecyclerView as used in an email app, and the screenshot on the right
is an example of CardView as used in a travel reservation app.
RecyclerView
RecyclerView is similar to ListView, but it is better suited for large sets of views or lists with elements that
change dynamically. Like ListView, you specify an adapter to access the underlying data set. However, unlike
ListView, you use a layout manager to position items within RecyclerView . The layout manager also takes care
of view recycling; it manages the reuse of item views that are no longer visible to the user.
When you use a RecyclerView widget, you must specify a LayoutManager and an adapter. As shown in this figure,
LayoutManager is the intermediary between the adapter and the RecyclerView :
The following screenshots illustrate a RecyclerView that contains 100 items (each item consists of an ImageView
and a TextView ):
RecyclerView handles this large data set with ease – scrolling from the beginning of the list to end of the list in
this sample app takes only a few seconds. RecyclerView also supports animations; in fact, animations for adding
and removing items are enabled by default. When an item is added to a RecyclerView , it fades in as shown in this
sequence of screenshots:
For more about RecyclerView , see RecyclerView.
CardView
CardView is a simple view that simulates a floating card with rounded corners. Because CardView has built-in
view shadows, it provides an easy way for you to add visual depth to your app. The following screenshots show
three text-oriented examples of CardView :
Each of the cards in the above example contains a TextView ; the background color is set via the
cardBackgroundColor attribute.
Enhanced Notifications
The notification system in Android 5.0 has been significantly updated with a new visual format and new features.
Notifications have a new look in Android 5.0. For example, notifications in Android 5.0 now use dark text over a
light background:
When a large icon is displayed in a notification (as shown in the above example), Android 5.0 presents the small
icon as a badge over the large icon.
In Android 5.0, notifications can also appear on the device lockscreen. For example, here is an example screenshot
of a lockscreen with a single notification:
Users can double-tap a notification on the lockscreen to unlock the device and jump to the app that originated
that notification, or swipe to dismiss the notification. Notifications have a new visibility setting that determines
how much content can be displayed on the lockscreen. Users can choose whether to allow sensitive content to be
shown in lockscreen notifications.
Android 5.0 introduces a new high-priority notification presentation format called Heads-up. Heads-up
notifications slide down from the top of the screen for a few seconds and then retreat back to the notification
shade at the top of the screen. Heads-up notifications make it possible for the system UI to put important
information in front of the user without disrupting the currently running activity. The following example illustrates
a simple Heads-up notification that displays on top of an app:
New APIs
In addition to the new look-and-feel features described above, Android 5.0 adds new APIs that extend the
capabilities of existing multimedia, storage, and wireless/connectivity functionality. Also, Android 5.0 includes new
APIs that provide support for a new job scheduler feature.
Camera
Android 5.0 provides several new APIs for enhanced camera capabilities. The new Android.Hardware.Camera2
namespace includes functionality for accessing individual camera devices connected to an Android device. Also,
Android.Hardware.Camera2 models each camera device as a pipeline: it accepts a capture request, captures the
image, and then outputs the result. This approach makes it possible for apps to queue multiple capture requests
to a camera device.
The following APIs make these new features possible:
CameraManager.GetCameraIdList – Helps you to programmatically access camera devices; you use
CameraManager.OpenCamera to connect to a specific camera device.
CameraCaptureSession – Captures or streams images from the camera device. You implement a
CameraCaptureSession.CaptureListener interface to handle new image capture events.
For more about the new camera APIs in Android 5.0, see Media.
Audio Playback
Android 5.0 updates the AudioTrack class for better audio playback:
ENCODING_PCM_FLOAT – Configures AudioTrack to accept audio data in floating-point format for better
dynamic range, greater headroom, and higher quality (thanks to increased precision). Also, floating-point
format helps to avoid audio clipping.
ByteBuffer – You can now supply audio data to AudioTrack as a byte array.
WRITE_NON_BLOCKING – This option simplifies buffering and multithreading for some apps.
Also, you can use the new Android.App.Notification.MediaStyle class to associate a media session with rich
notification content (such as extracting and showing album art).
For more about the new media playback control features in Android 5.0, see Media.
Storage
Android 5.0 updates the Storage Access Framework to make it easier for applications to work with directories
and documents:
To select a directory subtree, you can build and send an Android.Intent.Action.OPEN_DOCUMENT_TREE intent.
This intent causes the system to display all provider instances that support subtree selection; the user then
browses and selects a directory.
To create and manage new documents or directories anywhere under a subtree, you use the new
CreateDocument , RenameDocument , and DeleteDocument methods of DocumentsContract .
To get paths to media directories on all shared storage devices, you call the new
Android.Content.Context.GetExternalMediaDirs method.
For more about new storage APIs in Android 5.0, see Storage.
Wireless & Connectivity
Android 5.0 adds the following API enhancements for wireless and connectivity:
New multi-network APIs that make it possible for apps to find and select networks with specific
capabilities before making a connection.
Bluetooth broadcasting functionality that enables an Android 5.0 device to act as a low -energy Bluetooth
peripheral.
NFC enhancements that make it easier to use near-field communications functionality for sharing data
with other devices.
For more about the new wireless and connectivity APIs in Android 5.0, see Wireless and Connectivity.
Job Scheduling
Android 5.0 introduces a new JobScheduler API that can help users minimize battery drain by scheduling certain
tasks to run only when the device is plugged in and charging. This job scheduler feature can also be used for
scheduling a task to run when conditions are more suitable to that task, such as downloading a large file when
the device is connected over a Wi-Fi network instead of a metered network.
For more about the new job scheduling APIs in Android 5.0, see Scheduling Jobs.
Summary
This article provided an overview of important new features in Android 5.0 for Xamarin.Android app developers:
Material Theme
Animations
View shadows and elevation
Color features, such as drawable tinting and prominent color extraction
The new RecyclerView and CardView widgets
Notification enhancements
New APIs for camera, audio playback, media control, storage, wireless/connectivity, and job scheduling
If you are new to Xamarin Android development, read Setup and Installation to help you get started with
Xamarin.Android. Hello, Android is an excellent introduction for learning how to create Android projects.
Related Links
Android L Developer Preview
Get the Android SDK
Material Design
Material Design Principles
KitKat Features
4/12/2018 • 21 minutes to read • Edit Online
Android 4.4 (KitKat) comes loaded with a cornucopia of features for users and developers. This guide highlights
several of these features and provides code examples and implementation details to help you make the most out
of KitKat.
Overview
Android 4.4 (API Level 19), also known as "KitKat", was released in late 2013. KitKat offers a variety of new
features and improvements, including:
User Experience – Easy animations with transition framework, translucent status and navigation bars, and
full-screen immersive mode help create a better experience for the user.
User Content – User file management simplified with storage access framework; printing pictures, web
sites, and other content is easier with improved printing APIs.
Hardware – Turn any app into an NFC card with NFC Host-Based Card Emulation; run low -power sensors
with the SensorManager .
Developer Tools – Screencast applications in action with the Android Debug Bridge client, available as part
of the Android SDK.
This guide provides guidance for migrating an existing Xamarin.Android application to KitKat, as well as a high-
level overview of KitKat for Xamarin.Android developers.
Requirements
To develop Xamarin.Android applications using KitKat, you need Xamarin.Android 4.11.0 or higher and Android
4.4 (API Level 19) installed via the Android SDK Manager, as illustrated by the following screenshot:
Migrating Your App to KitKat
This section provides some first-response items to help transition existing applications to Android 4.4.
Check System Version
If an application needs to be compatible with older versions of Android, be sure to wrap any KitKat-specific code in
a system version check, as illustrated by the code sample below:
Alarm Batching
Android uses alarm services to wake an app in the background at a specified time. KitKat takes this a step further
by batching alarms to preserve power. This means that, in lieu of waking each app at an exact time, KitKat prefers
to group several applications that are registered to wake during the same time interval, and wake them at the same
time. To tell Android to wake an app during a specified time interval, call SetWindow on the AlarmManager , passing
in the minimum and maximum time, in milliseconds, that can elapse before the app is woken, and the operation to
perform at wakeup. The following code provides an example of an application that needs to be woken between a
half hour and an hour from the time the window is set:
To continue waking an app at an exact time, use SetExact , passing in the exact time that the app should be woken,
and the operation to perform:
alarmManager.SetExact (AlarmType.Rtc, AlarmManager.IntervalDay, pendingIntent);
KitKat no longer lets you set an exact repeating alarm. Applications that use SetRepeating and require exact alarms
to work will now need to trigger each alarm manually.
External Storage
External storage is now divided into two types - storage unique to your application, and data shared by multiple
applications. Reading and writing to your app's specific location on external storage requires no special
permissions. Interacting with data on shared storage now requires the READ_EXTERNAL_STORAGE or
WRITE_EXTERNAL_STORAGE permission. The two types can be classified as such:
If you're getting a file or directory path by calling a method on Context - for example, GetExternalFilesDir
or GetExternalCacheDirs
your app requires no extra permissions.
If you're getting a file or directory path by accessing a property or calling a method on Environment , such
as GetExternalStorageDirectory or GetExternalStoragePublicDirectory , your app requires the
READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE permission.
NOTE
WRITE_EXTERNAL_STORAGE implies the READ_EXTERNAL_STORAGE permission, so you should only ever need to set one
permission.
SMS Consolidation
KitKat simplifies messaging for the user by aggregating all SMS content in one default application selected by the
user. The developer is responsible for making the app selectable as the default messaging application, and
behaving appropriately in code and in life if the application is not selected. For more information on transitioning
your SMS app to KitKat, refer to the Getting Your SMS Apps Ready for KitKat guide from Google.
WebView Apps
WebView got a makeover in KitKat. The biggest change is added security for loading content into a WebView .
While most applications targeting older API versions should work as expected, testing applications that use the
WebView class is highly recommended. For more information about affected WebView APIs refer to the Android
Migrating to WebView in Android 4.4 documentation.
User Experience
KitKat comes with several new APIs to enhance user experience, including the new transition framework for
handling property animations and a translucent UI option for theming. These changes are covered below.
Transition Framework
The transition framework makes animations easier to implement. KitKat lets you perform a simple property
animation with just one line of code, or customize transitions using Scenes.
Simple Property Animation
The new Android Transitions library simplifies the code behind property animations. The framework allows you to
perform simple animations with minimal code. For example, the following code sample uses
TransitionManager.BeginDelayedTransition to animate showing and hiding a TextView :
using Android.Transitions;
TransitionManager.BeginDelayedTransition (linear);
if(text.Visibility != ViewStates.Visible)
{
text.Visibility = ViewStates.Visible;
}
else
{
text.Visibility = ViewStates.Invisible;
}
};
}
}
The example above uses the transition framework to create an automatic, default transition between the changing
property values. Because the animation is handled by a single line of code, you can easily make this compatible
with older versions of Android by wrapping the BeginDelayedTransition call in a system version check. See the
Migrating Your App To KitKat section for more.
The screenshot below shows the app before the animation:
The screenshot below shows the app after the animation:
You can get more control over the transition with Scenes, which are covered in the next section.
Android Scenes
Scenes were introduced as part of the transition framework to give the developer more control over animations.
Scenes create a dynamic area in the UI: you specify a container and several versions, or "scenes", for the XML
content inside the container, and Android does the rest of the work to animate the transitions between the scenes.
Android Scenes let you build complex animations with minimal work on the development side.
The static UI element housing the dynamic content is a called a container or scene base. The example below uses
the Android Designer to create a RelativeLayout called container :
The sample layout also defines a button called sceneButton below the container . This button will trigger the
transition.
The dynamic content inside the container requires two new Android layouts. These layouts specify only the code
inside the container. The example code below defines a layout called Scene1 that contains two text fields reading
"Kit" and "Kat" respectively, and a second layout called Scene2 that contains the same text fields reversed. The XML
is as follows:
Scene1.axml:
Scene2.axml:
The example above uses merge to make the view code shorter and simplify the view heirarchy. You can read more
about merge layouts here.
A Scene is created by calling Scene.GetSceneForLayout , passing in the container object, the Resource ID of the
Scene's layout file, and the current Context , as illustrated by the code example below:
scene1.Enter();
Clicking on the button flips between the two Scenes, which Android animates with the default transition values:
TransitionManager.Go (scene1);
};
C u st o m T r a n si t i o n s i n Sc e n e s
A custom transition can be defined in an xml resource file in the transition directory under Resources , as
illustrated by the screenshot below:
The following code sample defines a transition that animates for 5 seconds and uses the overshoot interpolator:
<changeBounds
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="5000"
android:interpolator="@android:anim/overshoot_interpolator" />
The transition is created in the Activity using the TransitionInflater, as illustrated by the code below:
The new transition is then added to the Go call that begins the animation:
Translucent UI
KitKat gives you more control over theming your app with optional transclucent status and navigation bars. You
can change the translucency of system UI elements in the same XML file you use to define your Android theme.
KitKat introduces the following properties:
windowTranslucentStatus - When set to true, makes the top status bar translucent.
windowTranslucentNavigation - When set to true, makes the bottom navigation bar translucent.
fitsSystemWindows - Setting the top or bottom bar to transcluent shifts content under the transparent UI
elements by default. Setting this property to true is a simple way to prevent content from overlapping with
the translucent system UI elements.
The following code defines a theme with translucent status and navigation bars:
The screenshot below shows the theme above with translucent status and navigation bars:
User Content
Storage -Access Framework
The Storage Access Framework (SAF ) is a new way for users to interact with stored content such as images,
videos, and documents. Instead of presenting users with a dialog to choose an application to handle content, KitKat
opens a new UI that allows users to access their data in one aggregate location. Once content has been chosen, the
user will return to the application that requested the content, and the app experience will continue as normal.
This change requires two actions on the developer side: first, apps that require content from providers need to be
updated to a new way of reqesting content. Second, applications that write data to a ContentProvider need to be
modified to use the new framework. Both scenarios depend on the new DocumentsProvider API.
DocumentsProvider
In KitKat, interactions with ContentProviders are abstracted with the DocumentsProvider class. This means that SAF
doesn't care where the data is physically, as long as it is accessible through the DocumentsProvider API. Local
providers, cloud services, and external storage devices all use the same interface, and are treated the same way,
providing the user and the developer with one place to interact with the user's content.
This section covers how to load and save content with the Storage Access Framework.
Request Content From a Provider
We can tell KitKat that we want to pick content using the SAF UI with the ActionOpenDocument Intent, which
signifies that we want to connect to all content providers available to the device. You can add some filtering to this
Intent by specifying CategoryOpenable , which means only content that can be opened (i.e. accessible, usable
content) will be returned. KitKat also allows filtering of content with the MimeType . For example, the code below
filters for image results by specifying the image MimeType :
Calling StartActivityForResult launches the SAF UI, which the user can then browse to choose an image:
After the user has chosen an image, OnActivityResult returns the Android.Net.Uri of the chosen file. The code
sample below displays the user's image selection:
The above code sample loads the SAF UI, letting the user change the file name and select a directory to house the
new file:
When the user presses Save, OnActivityResult gets passed the Android.Net.Uri of the newly created file, which
can be accessed with data.Data . The uri can be used to stream data into the new file:
P r i n t Men u It em
The print option will typically appear in the Activity's options menu. The options menu lets users perform actions
on an Activity. It is in the top right corner of the screen, and looks like this:
Additonal menu items can be defined in the menudirectory under Resources. The code below defines a sample
menu item called Print:
Interaction with the options menu in the Activity happens through the OnCreateOptionsMenu and
OnOptionsItemSelected methods. OnCreateOptionsMenu is the place to add new menu items, like the Print option,
from the menu resources directory. OnOptionsItemSelected listens for the user selecting the Print option from the
menu, and begins printing:
bool dataLoaded;
The code above also defines a variable called dataLoaded to keep track of the status of the HTML content. The
WebViewClient will set this variable to true when all content has loaded, so the Activity knows to add the Print
menu item to the options menu.
W e b Vi e w C l i e n t
The job of the WebViewClient is to ensure data in the WebView is fully loaded before the print option appears in the
menu, which it does with the OnPageFinished method. OnPageFinished listens for web content to finish loading,
and tells the Activity to recreate its options menu with InvalidateOptionsMenu :
class MyWebViewClient : WebViewClient
{
PrintHtmlActivity caller;
OnPageFinished also sets the dataLoaded value to true , so OnCreateOptionsMenu can recreate the menu with the
Print option in place.
Pr i n t Man ager
void PrintPage ()
{
PrintManager printManager = (PrintManager)GetSystemService (Context.PrintService);
PrintDocumentAdapter printDocumentAdapter = myWebView.CreatePrintDocumentAdapter ();
printManager.Print ("MyWebPage", printDocumentAdapter, null);
}
Print takes as arguments: a name for the print job ("MyWebPage" in this example), a PrintDocumentAdapter that
generates the print document from the content, and PrintAttributes ( null in the example above). You can
specify PrintAttributes to help lay out content on the printed page, although the default attributes should handle
most scenarions.
Calling Print loads the print UI, which lists options for the print job. The UI gives users the option of printing or
saving the HTML content to a PDF, as illustrated by the screenshots below:
Hardware
KitKat adds several APIs to accomodate new device features. The most notable of these are Host-Based Card
Emulation and the new SensorManager .
Host-Based Card Emulation in NFC
Host-Based Card Emulation (HCE ) allows applications to behave like NFC cards or NFC card readers without
relying on the carrier's proprietary Secure Element. Before setting up HCE, ensure HCE is available on the device
with PackageManager.HasSystemFeature :
HCE requires that both the HCE feature and the Nfc permission be registered with the application's
AndroidManifest.xml :
<uses-feature android:name="android.hardware.nfc.hce" />
To work, HCE has to be able to run in the background, and it has to start when the user makes an NFC transaction,
even if the application using HCE is not running. We can accomplish this by writing the HCE code as a Service .
An HCE Service implements the HostApduService interface, which implements the following methods:
ProcessCommandApdu - An Application Protocol Data Unit (APDU ) is what gets sent between the NFC
Reader and the HCE Service. This method consumes an ADPU from the reader, and returns a data unit in
response.
OnDeactivated - The HostAdpuService is deactivated when the HCE Service is no longer communicating
with the NFC Reader.
An HCE Service also needs to be registered with the application's manifest, and decorated with the proper
permissons, intent filter, and metadata. The following code is an example of a HostApduService registered with the
Android Manifest using the Service attribute (for more information on attributes, refer to the Xamarin Working
with Android Manifest guide):
[Service(Exported=true, Permission="android.permissions.BIND_NFC_SERVICE"),
IntentFilter(new[] {"android.nfc.cardemulation.HOST_APDU_SERVICE"}),
MetaData("andorid.nfc.cardemulation.host.apdu_service",
Resource="@xml/hceservice")]
The above Service provides a way for the NFC reader to interact with the application, but the NFC reader still has
no way of knowing if this Service is emulating the NFC card it needs to scan. To help the NFC reader identify the
Service, we can assign the Service a unique Application ID (AID ). We specify an AID, along with other metadata
about the HCE Service, in an xml resource file registered with the MetaData attribute (see code example above).
This resource file specifies one or more AID filters - unique identifier strings in hexadecimal format that
correspond to the AIDs of one or more NFC reader devices:
<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/hce_service_description"
android:requireDeviceUnlock="false"
android:apduServiceBanner="@drawable/service_banner">
<aid-group android:description="@string/aid_group_description"
android:category="payment">
<aid-filter android:name="1111111111111111"/>
<aid-filter android:name="0123456789012345"/>
</aid-group>
</host-apdu-service>
In addition to AID filters, the xml resource file also provides a user-facing description of the HCE Service, specifies
an AID group (payment application versus "other") and, in the case of a payment application, a 260x96 dp banner
to display to the user.
The setup outlined above provides the basic building blocks for an application emulating an NFC card. NFC itself
requires several more steps and further testing to configure. For more information on Host-based Card Emulation,
refer to the Android documentation portal. For more information on using NFC with Xamarin, check out the
Xamarin NFC samples.
Sensors
KitKat provides access to the device's sensors through a SensorManager . The SensorManager allows the OS to
schedule the delivery of sensor information to an application in batches, preserving battery life.
KitKat also ships with two new sensor types for tracking the user's steps. These are based on accelerometer and
include:
StepDetector - App is notified/woken when the user takes a step, and the detector provides a time value for
when the step occurred.
StepCounter - Keeps track of the number of steps the user has taken since the sensor was registered until
the next device reboot.
The screenshot below depicts the step counter in action:
You can create a SensorManager by calling GetSystemService(SensorService) and casting the result as a
SensorManager . To use the step counter, call GetDeafultSensor on the SensorManager . You can register the sensor
and listen to changes in step count with the help of the ISensorEventListener interface, as illustrated by the code
sample below:
public class MainActivity : Activity, ISensorEventListener
{
float count = 0;
OnSensorChanged is called if the step count updates while the application is in the foreground. If the application
enters the background, or the device is asleep, OnSensorChanged will not be called; however, the steps will continue
to be counted until UnregisterListener is called.
Keep in mind that the step count value is cumulative across all applications that register the sensor. This means
that even if you uninstall and reinstall your application, and initialize the count variable at 0 at application startup,
the value reported by the sensor will remain the total number of steps taken while the sensor was registered,
whether by your application or another. You can prevent your application from adding to the step counter by
calling UnregisterListener on the SensorManager , as illustrated by the code below:
Rebooting the device resets the step count to 0. Your app will require extra code to ensure it is reporting an
accurate count for the application, regardless of other applications using the sensor or the state of the device.
NOTE
While the API for the step detection and counting ships with KitKat, not all phones are outfitted with the sensor. You can
check if the sensor is available by running
PackageManager.HasSystemFeature(PackageManager.FeatureSensorStepCounter); , or check to ensure the returned value
of GetDefaultSensor isn't null .
Developer Tools
Screen Recording
KitKat includes new screen recording capabilities so that developers can record applications in action. Screen
recording is available through the Android Debug Bridge (ADB ) client, which can be downloaded as part of the
Android SDK.
To record your screen, connect your device; then, locate your Android SDK installation, navigate to the platform -
tools directory and run the adb client:
The above command will record a default 3-minute video at the default resolution of 4Mbps. To edit the length,
add the --time-limit flag. To change the resolution, add the --bit-rate flag. The following command will record a
minute-long video at 8Mbps:
You can find your video on your device - it will appear in your Gallery when the recording is complete.
Mirror Drawable Resources - Drawable resources have a new autoMirrored attribute that tells the system
create a mirrored version for images that require flipping for left-to-right layouts.
Pause Animations - Pause and resume animations created with the Animator class.
Read Dynamically Changing Text - Denote parts of UI that update dynamically with new text as "live
regions" with the new accesibilityLiveRegion attribute so the new text will be read automatically in
accessibility mode.
Enhance Audio Experience - Make tracks louder with the LoudnessEnhancer , find the Peak and RMS of an
audio stream with the Visualizer class, and get information from an audio timestamp to help with audio-
video synchronization.
Sync ContentResolver at Custom Interval - KitKat adds some variability to the time that a sync request is
performed. Sync a ContentResolver at custom time or interval by calling ContentResolver.RequestSync and
passing in a SyncRequest .
Distinguish Between Controllers - In KitKat, controllers are assigned unique integer identifiers that can be
accessed through the device's ControllerNumber property. This makes it easier to tell apart players in a
game.
Remote Control - With a few changes on both the hardware and software side, KitKat allows you to turn a
device outfitted with an IR transmitter into a remote control using the ConsumerIrService , and interact with
peripheral devices with the new RemoteController APIs.
For more information on the above API changes, please refer to the the Google Android 4.4 APIs overview.
Summary
This article introduced some of the new APIs available in Android 4.4 (API Level 19), and covered best practices
when transitioning an application to KitKat. It outlined changes to the APIs affecting user experience, including the
transition framework and new options for theming. Next, it introduced the Storage-Access Framework and
DocumentsProvider class, as well as the new printing APIs. It explored NFC host-based card emulation and how to
work with low -power sensors, including two new sensors for tracking the user's steps. Finally, it demonstrated
capturing real-time demos of applications with screen recording, and provided a detailed list of KitKat API changes
and additions.
Related Links
KitKat Sample
Android 4.4 APIs
Android KitKat
Jelly Bean Features
4/12/2018 • 11 minutes to read • Edit Online
This document will provide a high level overview of the new features for developers that were introduced in
Android 4.1. These features include: enhanced notifications, updates to Android Beam to share large files, updates
to multimedia, peer-to -peer network discovery, animations, new permissions.
Overview
Android 4.1 (API Level 16), also known as "Jelly Bean", was release on July 9th, 2012. This article will provide a
high level introduction to some of the new features in Android 4.1 for developers using Xamarin.Android. Some of
these new features introduced are enhancements to animations for launching an activity, new sounds for a camera,
and improved support for application stack navigation. It is now possible to cut and paste with intents.
The stability of Android applications is improved with the ability to isolate the dependency on unstable content
providers. Services may also be isolated so that they are accessible only by the activity that started them.
Support has been added for network service discovery using Bonjour, UPnP, or multicast DNS based services. It is
now possible for richer notifications that have formatted text, action buttons and large images.
Finally several new permissions have been added in Android 4.1.
Requirements
To develop Xamarin.Android applications using Jelly Bean requires Xamarin.Android 4.2.6 or higher and Android
4.1 (API Level 16) be installed via the Android SDK Manager as shown in the following screen shot:
What's New
Animations
Activities may be launched using either zoom animations or custom animations by using the ActivityOptions
class. The following new methods are provided to support these animations:
MakeScaleUpAnimation – This will create an animation that scales up an activity window from a start position and
size on the screen.
MakeThumbnailScaleUpAnimation – This will create an animation that scales up from a thumbnail image from
specified position on the screen.
MakeCustomAnimation – This creates an animation from resources in the application. There is one animation for
when the activity opens and another for when the activity stops.
The new TimeAnimator class provides an interface TimeAnimator.ITimeListener that can notify an application every
time a frame changes in an animation. For example, consider the following implementation of
TimeAnimator.ITimeListener :
class MyTimeListener : Java.Lang.Object, TimeAnimator.ITimeListener
{
public void OnTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime)
{
Log.Debug("Activity1", "totalTime={0}, deltaTime={1}", totalTime, deltaTime);
}
}
And now to use the class, an instance of TimeAnimator is created, and the listener is set:
As the TimeAnimator instance is running, it will invoke ITimeAnimator.ITimeListener , which will then log the how
long the animator has been running and how long it as been since the last time the method has been invoked.
Application Stack Navigation
Android 4.1 improves on the application stack navigation that was introduced in Android 3.0. By specifying the
ParentName property of the ActivityAttribute , Android can open the proper parent Activity when the user
presses the Up button on the action bar - Android will instantiate the Activity specified by the ParentName
property. This allows applications to preserve hierarchy of activities that make a given task.
For most applications setting the ParentName on the activity is sufficient information for Android to provide the
correct behavior for navigating the application stack; Android will synthesize the necessary back stack by creating a
series of Intents for each parent activity. However, because this is an artificial application stack, each synthetic
activity will not have the saved state that a natural activity would have. To provide saved state to a synthetic parent
activity, an Activity may override the OnPrepareNavigationUpTaskStack method. This method receives a
TaskStackBuilder instance that will have a collection of Intent objects that Android will use to create the back
stack. The activity may modify these Intents so that, as the synthetic activity is created, it will receive the proper
state information.
For more complex scenarios, there are new methods on the Activity class that may be used to handle the behavior
of Up navigation and construct the back stack:
OnNavigateUp – By overriding this method it is possible to perform a custom action when the Up button is
pressed.
NavigateUpTo – Calling this method will cause the application to navigate from the current activity to the
activity specified by a given intent.
ParentActivityIntent – This is used to obtain an Intent that will launch the parent activity of the current activity.
ShouldUpRecreateTask – This method is used to query if the synthetic back stack must be created to navigate up
to a parent activity. Returns true if the synthetic stack must be created.
FinishAffinity – Calling this method will finish the current activity and all activities below it in the current task
that have the same task affinity.
OnCreateNavigateUpTaskStack – This method is overridden when it is necessary to have complete control over
how the synthetic stack is created.
Camera
There is a new interface, Camera.IAutoFocusMoveCallback , which can be used to detect when the auto focus has
started or stopped moving. An example of this new interface can be seen in the following snippet:
public class AutoFocusCallbackActivity : Activity, Camera.IAutoFocusCallback
{
public void OnAutoFocus(bool success, Camera camera)
{
// camera is an instance of the camera service object.
if (success)
{
// Auto focus was successful - do something here.
}
else
{
// Auto focus didn't happen for some reason - react to that here.
}
}
}
The new class MediaActionSound provides a set of API's for producing sounds for the various media actions. There
are several actions that can occur with a camera, these are defined by the enum
Android.Media.MediaActionSoundType :
An example of how to use the MediaActionSound class can be seen in the following snippet:
Connectivity
Android Beam
Android Beam is an NFC based technology that allows two Android devices to communicate with each other.
Android 4.1 provides better support for the transfer of large files. When using the new method
NfcAdapter.SetBeamPushUris() Android will switch between alternate transport mechanisms (such as Bluetooth) to
achieve a fast transfer speed.
Network Services Discovery
Android 4.1 contains new API’s for multicast DNS -based service discovery. This allows an application to detect
and connect over Wi-Fi to other devices such as printers, cameras, and media devices. These new API’s are in the
Android.Net.Nsd package.
To create a service that may be consumed by other services, the NsdServiceInfo class is used to create an object
that will define the properties of a service. This object is then provided to NsdManager.RegisterService() along with
an implementation of NsdManager.ResolveListener . Implementations of NsdManager.ResolveListener are used to
notify of a successful registration and to unregister the service.
To discover services on the network, and implementation of Nsd.DiscoveryListener passed to
NsdManager.discoverServices() .
Network Usage
A new method, ConnectivityManager.IsActiveNetworkMetered allows a device to check if it is connected to a metered
network. This method can be used to help manage data usage by accurately informing users that there might be
expensive charges for data operations.
WiFi Direct Service Discovery
The WifiP2pManager class was introduced in Android 4.0 to support zeroconf. Zeroconf (zero configuration
networking) is a set of techniques that allows devices (computers, printers, phones) to connect to networks
automatically, with the intervention of human network operators or special configuration servers.
In Jelly Bean, WifiP2pManager can discover nearby devices using either Bonjour or Upnp. Bonjour is Apple’s
implementation of zeroconf. Upnp is set of networking protocols that also supports zeroconf. The following
methods added to the WiFiP2pManager to support Wi-Fi service discovery:
AddLocalService() – This method is used announce an application as a service over Wi-Fi for discovery by
peers.
AddServiceRequest( ) – This method is to send a service discovery request to the framework. It is used to
initialize the Wi-Fi service discovery.
SetDnsSdResponseListeners() – This method is used to register callbacks to be invoked on receiving a response
to discovery requests from Bonjour.
SetUpnpServiceResponseListener() – This method is used to register callbacks to be invoked on receiving a
response to discovery requests Upnp.
Content Providers
The ContentResolver class has received a new method, AcquireUnstableContentProvider . This method allows an
application to acquire an “unstable” content provider. Normally, when an application acquires a content provider,
and that content provider crashes, so will the application. With this method call, an application will not crash if the
content provider crashes. Instead, Android.OS.DeadObjectionException will be thrown from calls on the content
provider to inform an application that the content provider has gone away. An “unstable” content provider is useful
when interacting with content providers from other applications – it is less likely that buggy code from another
application will affect another application.
Copy and Paste With Intents
The Intent class can now have a ClipData object associated with it via the Intent.ClipData property. This
method allows for extra data from the clipboard to be transmitted with the intent. An instance of ClipData can
contain one or more ClipData.Item . ClipData.Item ’s are items of the following types:
Text – This is any string of text, either HTML or any string whose format is supported by the built-in Android
style spans.
Intent – Any Intent object.
Uri – This can be any URI, such as an HTTP bookmark or the URI to a content provider.
Isolated Services
An isolated service is a service that runs under its own special process and has no permissions of its own. The only
communication with the service is when starting up the service and binding to it via the Service API. It is possible
to declare a service as isolated by setting the property IsolatedProcess="true" in the ServiceAttribute that
adorns a service class.
Media
The new Android.Media.MediaCodec class provides an API to low -level media codecs. Applications can query the
system to find out what low level codecs are available on the device.
The new Android.Media.Audiofx.AudioEffect subclasses have been added to support additional audio pre-
processing on captured audio:
Android.Media.Audiofx.AcousticEchoCanceler – This class is used for pre-processing audio to remove the signal
from a remote party from a captured audio signal. For example, removing the echo from a voice
communication application.
Android.Media.Audiofx.AutomaticGainControl – This class is used to normalize the captured signal by boosting or
lowering an input signal so that the output signal is constant.
Android.Media.Audiofx.NoiseSuppressor – This class will remove background noise from the captured signal.
Not all devices will support these effects. The method AudioEffect.IsAvailable should be called by an application
to see if the audio effect in question is supported on the device running the application.
The MediaPlayer class now supports gapless playback with the SetNextMediaPlayer() method. This new method
specifies the next MediaPlayer to start when the current media player finishes its playback.
The following new classes provide standard mechanisms and UI for selecting where media will be played:
MediaRouter – This class allows applications to control the routing of media channels from a device to external
speakers or other devices.
MediaRouterActionProvider and MediaRouteButton – These classes help provide a consistent UI for selecting and
playing media.
Notifications
Android 4.1 allows applications more flexibility and control with displaying notifications. Applications can now
show bigger and better notifications to users. A new method, NotificationBuilder.SetStyle() allows for one of
new three new style to be set on notifications:
Notification.BigPictureStyle– This is a helper class that will generate notifications that will have an image in
them. The following image shows an example of a notification with a big image:
Notification.BigTextStyle – This is a helper class that will generate notifications that will have multiple lines of
text, such as e-mail. An example of this new notification style can be seen in the following screenshot:
Notification.InboxStyle– This is a helper class that will generate notifications that contain a list of strings, such
as snippets from an e-mail message, as shown in this screenshot:
It is possible to add up to two action buttons at the bottom of a notification message when the notification is using
the normal or larger style. An example of this can be seen in the following screenshot, where the action buttons are
visible at the bottom of the notification:
The Notification class has received new constants that allow a developer to specify one of five priority levels for a
notification. These can be set on a notification using the Priority property.
Permissions
The following new permissions have been added:
READ_EXTERNAL_STORAGE - The application requires read only access to external storage. Currently all applications
have read access by default, but future releases of Android will require applications explicitly request read
access.
READ_USER_DICTIONARY - Allows a read-access to the user's word dictionary.
READ_CALL_LOG - Allows an application to obtain information about incoming and outgoing calls by reading the
call log.
WRITE_CALL_LOG - Allows an application to write to the call log on the phone.
WRITE_USER_DICTIONARY - Allows an application to write to the user's word dictionary.
Summary
This article introduced some of the new API’s that are available in Android 4.1 (API Level 16). It highlighted some
of changes for animations and animating the launch of an activity, and introduced the new API’s for network
discovery of other devices using protocols such as Bonjour or UPnP. Other changes to the API were highlighted as
well, such as the ability to cut and paste data via intents, the ability to use isolated services or “unstable” content
providers.
This article then went on to introduce the updates to notifications, and discussed some of the new permissions that
have been introduced with Android 4.1
Related Links
Time Animation Example (sample)
Android 4.1 APIs
Tasks and Back Stacks
Navigation with Back and Up
Ice Cream Sandwich Features
4/12/2018 • 2 minutes to read • Edit Online
This article describes several of the new features available to application developers with the Android 4 API - Ice
Cream Sandwich. It covers several new user interface technologies and then examines a variety of new capabilities
that Android 4 offers for sharing data between applications and between devices.
Overview
Android OS version 4.0 (API Level 14) represents a major reworking of the Android Operating System and
includes a number of important changes and upgrades, including:
Updated User Interface – Several new UI features give developers more power and flexibility when they
create application user interfaces. These new features include: GridLayout , PopupMenu , Switch widget, and
TextureView .
Better Hardware Acceleration – 2D rendering now takes place on the GPU for all Android controls.
Additionally, hardware acceleration is on, by default, in all applications developed for Android 4.0.
New Data APIs – There’s new access to data that was not previously officially accessible, such as calendar data
and the user profile of the device owner.
App Data Sharing – Sharing data between applications and devices is now easier than ever via technologies
such as the ShareActionProvider , which makes it easy to create a sharing action from an Action Bar, and
Android Beam for Near Field Communications (NFC ) , which makes it a snap to share data across devices in
close proximity to each other.
In this article, we’re going to explore these features and other changes that have been made to the Android 4.0
API, and we’ll explain how to use each feature with Xamarin.Android.
Sharing Features
Android 4 includes several new technologies that let us share data across devices and across applications. It also
provides access to various types of data that were not previously available, such as calendar information and the
device owner’s user profile. In this section we’ll examine a variety of features offered by Android 4 that address
these areas including:
Android Beam – Allows data sharing via NFC.
ShareActionProvider – Creates a provider that allows developers to specify sharing actions from the Action
Bar.
User Profile – Provides access to profile data of the device owner.
Calendar API – Provides access to calendar data from the calendar provider.
x86 Emulators
ICS does not yet support development with an x86 emulator. x86 emulators are only supported with Android 2.3.3,
API level 10. See Configuring the x86 Emulator for more information.
Summary
This article covered a variety of the new technologies that are now available with Android 4. We reviewed new
user interface features such as the GridLayout, PopupMenu, and Switch widget. We also looked at some of the new
support for controlling the system UI, as well as how to work with the TextureView. Then we discussed a variety of
new sharing technologies. We covered how Android Beam let’s you share information across devices that use
NFC, discussed the new Calendar API, and also showed how to use the built in ShareActionProvider. Finally, we
examined how to use the ContactsContract provider to access user profile data.
Related Links
Ice Cream Sandwich Samples
TextureViewDemo (sample)
CalendarDemo (sample)
Tab Layout Tutorial
Ice Cream Sandwich
Android 4.0 Platform
Intro to ContentProviders
4/12/2018 • 2 minutes to read • Edit Online
The Android operating system uses content providers to facilitate access to shared data such as media files,
contacts and calendar information. This article introduces the ContentProvider class, and provides two examples
of how to use it.
Related Links
ContactsAdapter Demo (sample)
SimpleContentProvider (sample)
Content Providers Developers Guide
ContentProvider Class Reference
ContentResolver Class Reference
ListView Class Reference
CursorAdapter Class Reference
UriMatcher Class Reference
Android.Provider
ContactsContract Class Reference
How Content Providers Work
4/12/2018 • 2 minutes to read • Edit Online
Consuming a ContentProvider
ContentProviders expose their functionality through a Uri that is registered in the AndroidManifest.xml of the
application that publishes the data. There is a convention where the Uri and the data columns that are exposed
should be available as constants to make it easy to bind to the data. Android's built-in ContentProviders all provide
convenience classes with constants that reference the data structure in the Android.Providers namespace.
Built-In Providers
Android offers access to a wide range of system and user data using ContentProviders :
Browser – bookmarks and browser history (requires permission READ_HISTORY_BOOKMARKS and/or
WRITE_HISTORY_BOOKMARKS ).
Classes Overview
The primary classes used when working with a ContentProvider are shown here:
In this diagram, the ContentProvider implements queries and registers URI's that other applications use to locate
data. The ContentResolver acts as a 'proxy' to the ContentProvider (Query, Insert, Update, and Delete methods).
The SQLiteOpenHelper contains data used by the ContentProvider , but it is not directly exposed to consuming apps.
The CursorAdapter passes the cursor returned by the ContentResolver to display in a ListView . The UriMatcher is
a helper class that parses URIs when processing queries.
The purpose of each class is described below:
ContentProvider – Implement this abstract class's methods to expose data. The API is made available to
other classes and applications via the Uri attribute that is added to the class definition.
SQLiteOpenHelper – Helps implement the SQLite datastore that is exposed by the ContentProvider .
UriMatcher – Use UriMatcher in your ContentProvider implementation to help manage Uris that are used
to query the content.
ContentResolver – Consuming code uses a ContentResolver to access a ContentProvider instance. The
two classes together take care of the inter-process communication issues, allowing data to be easily shared
between applications. Consuming code never creates a ContentProvider class explicity; instead, the data is
accessed by creating a cursor based on a Uri exposed by the ContentProvider application.
CursorAdapter – Use CursorAdapter or SimpleCursorAdapter to display data accessed via a
ContentProvider .
The ContentProvider API allows consumers to perform a variety of operations on the data, such as:
Query data to return lists or individual records.
Modify individual records.
Add new records.
Delete records.
This document contains an example that uses a system-provided ContentProvider , as well as a simple read-only
example that implements a custom ContentProvider .
Using the Contacts ContentProvider
4/12/2018 • 5 minutes to read • Edit Online
Code that uses access data exposed by a ContentProvider doesn't require a reference to the ContentProvider class
at all. Instead, a Uri is used to create a cursor over the data exposed by the ContentProvider . Android uses the Uri
to search the system for the application that exposes a ContentProvider with that identifier. The Uri is a string,
typically in a reverse-DNS format such as com.android.contacts/data .
Rather than making developers remember this string, the Android Contacts provider exposes its metadata in the
android.provider.ContactsContract class. This class is used to determine the Uri of the ContentProvider as well as
the names of the tables and columns that can be queried.
Some data types also require special permission to access. The built-in contacts list requires the
android.permission.READ_CONTACTS permission in the AndroidManifest.xml file.
Regardless of which method is used to retrieve the cursor, these same objects are used as parameters as shown in
the ContactsProvider/ContactsAdapter.cs file:
This cursor will be managed by Android so you do not need to close it.
Using ContentResolver
Accessing ContentResolver directly to get a cursor against a ContentProvider can be done like this:
This cursor is unmanaged, so it must be closed when no longer required. Ensure that the code closes a cursor that
is open, otherwise an error will occur.
cursor.Close();
Alternatively, you can call StartManagingCursor() and StopManagingCursor() to 'manage' the cursor. Managed
cursors are automatically deactivated and re-queried when Activities are stopped and restarted.
Using CursorLoader
Applications built for Android 3.0 (API Level 11) or newer should use this method:
var loader = new CursorLoader (activity, uri, projection, null, null, null);
var cursor = (ICursor)loader.LoadInBackground();
The CursorLoader ensures that all cursor operations are done on a background thread, and can intelligently re-use
an existing cursor across activity instances when an activity is restarted (e.g. due to a configuration change) rather
that reload the data again.
Earlier Android versions can also use the CursorLoader class by using the v4 support libraries.
Then implement the BaseAdapter's methods using the contactList collection. The adapter is implemented just as
it would be with any other collection – there is no special handling here because the data is sourced from a
ContentProvider :
Activity activity;
public ContactsAdapter (Activity activity)
{
this.activity = activity;
FillContacts ();
}
public override int Count {
get { return contactList.Count; }
}
public override Java.Lang.Object GetItem (int position)
{
return null; // could wrap a Contact in a Java.Lang.Object to return it here if needed
}
public override long GetItemId (int position)
{
return contactList [position].Id;
}
public override View GetView (int position, View convertView, ViewGroup parent)
{
var view = convertView ?? activity.LayoutInflater.Inflate (Resource.Layout.ContactListItem, parent, false);
var contactName = view.FindViewById<TextView> (Resource.Id.ContactName);
var contactImage = view.FindViewById<ImageView> (Resource.Id.ContactImage);
contactName.Text = contactList [position].DisplayName;
if (contactList [position].PhotoId == null) {
contactImage = view.FindViewById<ImageView> (Resource.Id.ContactImage);
contactImage.SetImageResource (Resource.Drawable.ContactImage);
} else {
var contactUri = ContentUris.WithAppendedId (ContactsContract.Contacts.ContentUri, contactList
[position].Id);
var contactPhotoUri = Android.Net.Uri.WithAppendedPath (contactUri, Contacts.Photos.ContentDirectory);
contactImage.SetImageURI (contactPhotoUri);
}
return view;
}
The image is displayed (if it exists) using the Uri to the image file on the device. The application looks like this:
Using a similar code pattern, your application can access a wide variety of system data including the user's photos,
videos and music. Some data types require special permissions to be requested in the project's
AndroidManifest.xml.
Refer to the ListViews and Adapters for further information on implementing SimpleCursorAdapter .
Related Links
ContactsAdapter Demo (sample)
Creating a Custom ContentProvider
4/12/2018 • 9 minutes to read • Edit Online
The previous section demonstrated how to consume data from a built-in ContentProvider implementation. This
section will explain how to build a custom ContentProvider and then consume its data.
About ContentProviders
A content provider class must inherit from ContentProvider . It should consist of an internal data store that is used
to respond to queries and it should expose Uris and MIME Types as constants to help consuming code make valid
requests for data.
URI (Authority)
ContentProviders are accessed in Android using a Uri. An application that exposes a ContentProvider sets the Uris
that it will respond to in its AndroidManifest.xml file. When the application is installed, these Uris are registered
so that other applications can access them.
In Mono for Android, the content provider class should have a [ContentProvider] attribute to specify the Uri (or
Uris) that should be added to AndroidManifest.xml.
Mime Type
The typical format for MIME Types consists of two parts. Android ContentProviders commonly use these two
strings for the first part of the MIME Type:
1. vnd.android.cursor.item – to represent a single row, use the ContentResolver.CursorItemBaseType constant
in code.
2. vnd.android.cursor.dir – for multiple rows, use the ContentResolver.CursorDirBaseType constant in code.
The second part of the MIME Type is specific to your application, and should use a reverse-DNS standard with a
vnd. prefix. The sample code uses vnd.com.xamarin.sample.Vegetables .
Implementation
There are three steps to creating and consuming a custom ContentProvider :
1. Create a database class – Implement SQLiteOpenHelper .
2. Create a ContentProvider class – Implement ContentProvider with an instance of the database, metadata
exposed as constant values and methods to access the data.
3. Access the ContentProvider via its Uri – Populate a CursorAdapter using the ContentProvider , accessed
via its Uri.
As previously discussed, ContentProviders can be consumed from applications other than where they are defined.
In this example the data is consumed in the same application, but keep in mind that other applications can also
access it as long as they know the Uri and information about the schema (which is usually exposed as constant
values).
Create a Database
Most ContentProvider implementations will be based on a SQLite database. The example database code in
SimpleContentProvider/VegetableDatabase.cs creates a very simple two-column database, as shown:
The database implementation itself does not need any special considerations to be exposed with a ContentProvider
, however if you intend to bind the ContentProvider's data to a ListView control then a unique integer column
named _id must be part of the result set. See the ListViews and Adapters document for more details on using the
ListView control.
The rest of the code will form the actual content provider implementation that allows the data to be discovered and
queried.
This code is all private to the ContentProvider class. Refer to Google's UriMatcher documentation for further
information.
The GetType method must also be overridden. This method may be called to determine the content type that will
be returned for a given Uri. This might tell the consuming application how to handle that data.
public override String GetType(Android.Net.Uri uri)
{
switch (uriMatcher.Match(uri)) {
case GET_ALL:
return VEGETABLES_MIME_TYPE; // list
case GET_ONE:
return VEGETABLE_MIME_TYPE; // single item
default:
throw new Java.Lang.IllegalArgumentExceptoin ("Unknown Uri: " + uri);
}
}
That completes the basic ContentProvider implementation. Once the application has been installed, the data it
exposes will be available both inside the application but also to any other application that knows the Uri to
reference it.
// Create a SimpleCursorAdapter
adapter = new SimpleCursorAdapter(this, Android.Resource.Layout.SimpleListItem1, cursor, fromColumns,
toControlIds);
listView.Adapter = adapter;
Uri.WithAppendedPath(VegetableProvider.CONTENT_URI, id.ToString());
Related Links
SimpleContentProvider (sample)
Maps and Location
4/12/2018 • 2 minutes to read • Edit Online
Location Services
This guide introduces location-awareness in Android applications, and illustrates how to get the user's location
using the Android Location Service API, as well as the Fused Location Provider available with the Google Location
Services API.
Maps
This article discusses how to use maps and location with Xamarin.Android. It covers everything from leveraging
the built-in maps application to using the Google Maps Android API V2 directly. Additionally, it explains how to
use a single API to work with location services, which allows an application to obtain location fixes via cell tower
location, Wi-Fi or GPS.
Location Services
5/24/2018 • 13 minutes to read • Edit Online
This guide introduces location-awareness in Android applications and illustrates how to get the user's location
using the Android Location Service API, as well as the fused location provider available with the Google Location
Services API.
Location fundamentals
In Android, not matter what API you choose for working with location data, several concepts remain the same.This
section introduces Location Providers and location-related permissions.
Location providers
Several technologies are used internally to pinpoint the user's location. The hardware used depends on the type of
location provider selected for the job of collecting data. Android uses three location providers:
GPS Provider – GPS gives the most accurate location, uses the most power, and works best outdoors. This
provider uses a combination of GPS and assisted GPS (aGPS ), which returns GPS data collected by cellular
towers.
Network Provider – Provides a combination of WiFi and Cellular data, including aGPS data collected by
cell towers. It uses less power than the GPS Provider, but returns location data of varying accuracy.
Passive Provider – A "piggyback" option using providers requested by other applications or Services to
generate location data in an application. This is a less reliable but power-saving option ideal for applications
that don't require constant location updates to work.
Location providers are not always available. For example, we might want to use GPS for our application, but GPS
might be turned off in Settings, or the device might not have GPS at all. If a specific provider is not available,
choosing that provider might return null .
Location permissions
A location-aware application needs access a device's hardware sensors to receive GPS, Wi-Fi, and cellular data.
Access is controlled through appropriate permissions in the application's Android Manifest. There are two
permissions available – depending on your application's requirements and your choice of API, you will want to
allow one:
ACCESS_FINE_LOCATION – Allows an application access to GPS. Required for the GPS Provider and Passive
Provider options (Passive Provider needs permission to access GPS data collected by another application or
Service). Optional permission for the Network Provider.
ACCESS_COARSE_LOCATION – Allows an application access to Cellular and Wi-Fi location. Required for Network
Provider if ACCESS_FINE_LOCATION is not set.
For apps that target API version 21 (Android 5.0 Lollipop) or higher, you can enable ACCESS_FINE_LOCATION and still
run on devices that do not have GPS hardware. If your app requires GPS hardware, you should explicitly add an
android.hardware.location.gps uses-feature element to the Android Manifest. For more information, see the
Android uses-feature element reference.
To set the permissions, expand the Properties folder in the Solution Pad and double-click
AndroidManifest.xml. The permissions will be listed under Required Permissions:
Setting either of these permissions tells Android that your application needs permission from the user in order to
access to the location providers. Devices that run API level 22 (Android 5.1) or lower will ask the user to grant
these permissions each time the app is installed. On devices running API level 23 (Android 6.0) or higher, the app
should perform a run-time permission check before making a request of the location provider.
NOTE
Note: Setting ACCESS_FINE_LOCATION implies access to both coarse and fine location data. You should never have to set
both permissions, only the minimal permission your app requires to work.
This snippet is an example of how to check that an app has permission for the ACCESS_FINE_LOCATION permission:
The fused location provider is part of Google Play Services. The Google Play Services package must be installed
and configured properly in the application for the fused location provider API to work, and the device must have
the Google Play Services APK installed.
Before a Xamarin.Android application can use the fused location provider, it must add the
Xamarin.GooglePlayServices.Maps package to the project. In addition, the following using statements should
be added to any source files that reference the classes described below:
using Android.Gms.Common;
using Android.Gms.Location;
if (GoogleApiAvailability.Instance.IsUserResolvableError(queryResult))
{
// Check if there is a way the user can resolve the issue
var errorString = GoogleApiAvailability.Instance.GetErrorString(queryResult);
Log.Error("MainActivity", "There is a problem with Google Play Services on this device: {0} - {1}",
queryResult, errorString);
return false;
}
FusedLocationProviderClient
To interact with the fused location provider, a Xamarin.Android application must have an instance of the
FusedLocationProviderClient . This class exposes the necessary methods to subscribe to location updates and to
retrieve the last known location of the device.
The OnCreate method of an Activity is a suitable place to get a reference to the FusedLocationProviderClient , as
demonstrated in the following code snippet:
if (location == null)
{
// Seldom happens, but should code that handles this scenario
}
else
{
// Do something with the location
Log.Debug("Sample", "The latitude is " + location.Latitude);
}
}
The Location Service is best suited for applications that must run on devices that do not have Google Play Services
installed.
The Location Service is a special type of Service managed by the System. A System Service interacts with the
device hardware and is always running. To tap into location updates in our application, we will subscribe to location
updates from the system Location Service using a LocationManager and a RequestLocationUpdates call.
To obtain the user's location using Android Location Service involves several steps:
1. Get a reference to the LocationManager service.
2. Implement the ILocationListener interface and handle events when the location changes.
3. Use the LocationManager to request location updates for a specified provider. The ILocationListener from the
previous step will be used to receive callbacks from the LocationManager .
4. Stop location updates when the application it is no longer appropriate to receive updates.
Location Manager
We can access the system location service with an instance of the LocationManager class. LocationManager is a
special class that lets us interact with the system location Service and call methods on it. An application can get a
reference to the LocationManager by calling GetSystemService and passing in a Service type, as shown below:
// For this example, this method is part of a class that implements ILocationListener, described below
locationManager.RequestLocationUpdates(LocationManager.GpsProvider, 2000, 1, this);
An application should request location updates only as often as required for the application to perform well. This
preserves battery life and creates a better experience for the user.
Responding to updates from the LocationManager
Once an application has requested updates from the LocationManager , it can receive information from the Service
by implementing the ILocationListener interface. This interface provides four methods for listening to the location
Service and the location provider, OnLocationChanged . The System will call OnLocationChanged when the user's
location changes enough to qualify as a location change according to the Criteria set when requesting location
updates.
The following code shows the methods in the ILocationListener interface:
If your application needs to get location updates while in the background, you'll want to create a custom Service
that subscribes to the system Location Service. Refer to the Backgrounding with Android Services guide for more
information.
Determining the best location provider for the LocationManager
The application above sets GPS as the location provider. However, GPS may not be available in all cases, such as if
the device is indoors or does not have a GPS receiver. If this is the case, the result is a null return for the Provider.
To get your app to work when GPS is not available, you use the GetBestProvider method to ask for the best
available (device-supported and user-enabled) location provider at application launch. Instead of passing in a
specific provider, you can tell GetBestProvider the requirements for the provider - such as accuracy and power -
with a Criteria object. GetBestProvider returns the best provider for the given Criteria.
The following code shows how to get the best available provider and use it when requesting location updates:
if(locationProvider != null)
{
locationManager.RequestLocationUpdates (locationProvider, 2000, 1, this);
}
else
{
Log.Info(tag, "No location providers available");
}
NOTE
If the user has disabled all location providers, GetBestProvider will return null . To see how this code works on a real
device, be sure to enable GPS, Wi-Fi, and cellular networks under Google Settings > Location > Mode as shown in this
screenshot:
The screenshot below demonstrates the location application running using GetBestProvider :
Keep in mind that GetBestProvider does not change the provider dynamically. Rather, it determines the best
available provider once during the Activity lifecycle. If the provider status changes after it has been set, the
application will require additional code in the ILocationListener methods – OnProviderEnabled ,
OnProviderDisabled , and OnStatusChanged – to handle every possibility related to the provider switch.
Summary
This guide covered obtaining the user's location using both the Android Location Service and the fused location
provider from Google Location Services API.
Related Links
Location (sample)
FusedLocationProvider (sample)
Google Play Services
Criteria Class
LocationManager Class
LocationListener Class
LocationClient API
LocationListener API
LocationRequest API
How to use Google Maps and Location with
Xamarin.Android
6/25/2018 • 2 minutes to read • Edit Online
This article discusses how to use maps and location with Xamarin.Android. It covers everything from leveraging the
built-in maps application to using the Google Maps Android API V2 directly.
Maps Overview
Mapping technologies are a ubiquitous complement to mobile devices. Desktop computers and laptops don't tend
to have location awareness built-in. On the other hand, mobile devices use such applications to locate devices and
to display changing location information. Android has powerful, built-in technology that displays location data on
maps using location hardware that may be available on the device. This article covers a spectrum of what the maps
applications under Xamarin.Android have to offer, including:
Using the built-in maps application to quickly add mapping functionality.
Working with the Maps API to control a map's display.
Using a variety of techniques to add graphical overlays.
The topics in this section cover a wide range of mapping features. First, they explain how to leverage Android's
built-in maps application and how to display a panoramic street view of a location. Then they discuss how to use
the Maps API to incorporate mapping features directly within an application, covering both how to control the
position and display of a map, as well as how to add graphical overlays.
Related Links
MapsAndLocationDemo_v3 (sample)
Activity Lifecycle
Obtaining a Google Maps API Key
Intents List: Invoking Google Applications on Android Devices
Location and Maps
Launching the Maps Application
6/25/2018 • 2 minutes to read • Edit Online
The simplest way to work with maps in Xamarin.Android is to leverage the built-in maps application shown below:
When you use the maps application, the map will not be part of your application. Instead, your application will
launch the maps application and load the map externally. The next section examines how to use Xamarin.Android
to launch maps like the one above.
This code is all that is needed to launch the map shown in the previous screenshot. In addition to specifying latitude
and longitude, the URI scheme for maps supports several other options.
The versions of the URI that take a query (namely the street address or search terms) use Google's geocoder
service to retrieve the location that is then displayed on the map. For example, the URI geo:0,0?q=coop+Cambridge
results in the map shown below:
For more information about geo URI schemes, see Show a location on a map.
Street View
In addition to the geo scheme, Android also supports loading street views from an Intent. An example of the street
view application launched from Xamarin.Android is shown below:
To launch a street view, simply use the google.streetview URI scheme, as demonstrated in the following code:
The google.streetview URI scheme used above takes the following form:
google.streetview:cbll=lat,lng&cbp=1,yaw,,pitch,zoom&mz=mapZoom
As you can see, there are several parameters supported, as listed below:
lat – The latitude of the location to be shown in the street view.
lng – The longitude of the location to be shown in the street view.
pitch– Angle of street view panorama, measured from the center in degrees where 90 degrees is straight
down and -90 degrees is straight up.
yaw – Center-of-view of street view panorama, measured clockwise in degrees from North.
zoom– Zoom multiplier for street view panorama, where 1.0 = normal zoom, 2.0 = zoomed 2x, 3.0 =
zoomed 4x, etc.
mz – The map zoom level that will be used when going to the maps application from the street view.
Working with the built-in maps application or the street view is an easy way to quickly add mapping support.
However, Android's Maps API offers finer control over the mapping experience.
Using the Google Maps API in your application
6/25/2018 • 19 minutes to read • Edit Online
Using the Maps application is great, but sometimes you want to include maps directly in your application. In
addition to the built-in maps application, Google also offers a native mapping API for Android. The Maps API is
suitable for cases where you want to maintain more control over the mapping experience. Things that are possible
with the Maps API include:
Programmatically changing the viewpoint of the map.
Adding and customizing markers.
Annotating a map with overlays.
Unlike the now -deprecated Google Maps Android API v1, Google Maps Android API v2 is part of Google Play
Services. Therefore, it is necessary to meet some mandatory prerequisites before it is possible to use the Google
Maps Android API in a Xamarin.Android application.
The Android Maps API is provided as a part of Google Play Services. Before a Xamarin.Android application can
use the Maps API, the Google Play Services SDK must be installed and bound. The Google Play Services SDK is
installed through the Android SDK Manager. The following screenshot shows where in the Android SDK Manager
the Google Play services client can be found:
NOTE
The Google Play services APK is a licensed product that may not be present on all devices. If it is not installed, then Google
Maps will not work on the device.
This opens the NuGet Package Manager. Click Browse and enter Xamarin Google Play Services Maps in the
search field. Select Xamarin.GooglePlayServices.Maps and click Install. (If this package had been installed
previously, click Update.):
Notice that the following dependency packages are also installed:
Xamarin.GooglePlayServices.Base
Xamarin.GooglePlayServices.Basement
Xamarin.GooglePlayServices.Tasks
Create an Emulator with Google APIs
Although it is not recommended, it is possible to setup the emulator to support the Android Maps API. The
emulator must be configured to target the Google API Level 17 (Android 4.2.2) or higher. In the following
screenshot, an emulator image is configured for API Level 19:
<!-- We need to be able to download map tiles and access Google Play Services-->
<uses-permission android:name="android.permission.INTERNET" />
<!-- Google Maps for Android v2 will cache map tiles on external storage -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Google Maps for Android v2 needs this permission so that it may check the connection state as it must
download data -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Permission to receive remote notifications from Google Play Services -->
<!-- Notice here that we have the package name of our application as a prefix on the permissions. -->
<uses-permission android:name="<PACKAGE NAME>.permission.MAPS_RECEIVE" />
<permission android:name="<PACKAGE NAME>.permission.MAPS_RECEIVE" android:protectionLevel="signature" />
<!-- These are optional, but recommended. They will allow Maps to use the My Location provider. -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application android:label="@string/app_name">
<!-- Put your Google Maps V2 API Key here. -->
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="YOUR_API_KEY" />
<meta-data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
</application>
</manifest>
Each of these containers expose a Map property that returns an instance of GoogleMap . Preference should be given
to the MapFragment class as it is a simpler API that reduces the amount boilerplate code that a developer must
manually implement.
Adding a MapFragment to an Activity
The following screenshot is an example of a very simple MapFragment :
Similar to other Fragment classes, there are two ways to add this MapFragment to an Activity:
Declaratively - The MapFragment can be added via the XML layout file for the Activity. The following XML
snippet shows an example of how to use the fragment element:
To programmatically add a MapFragment , your Activity must implement the IOnMapReadyCallback interface. Because
the initialization of a GoogleMap object can take some time to complete as the API communicates with Google Play,
you must provide a callback that notifies your app when the GoogleMap is ready.
First, add IOnMapReadyCallback to the Activity class declaration. For example:
Next, in the OnCreate method, add the MapFragment as shown in the following code example (the
GoogleMapOptions class is explained later in this guide):
_mapFragment = FragmentManager.FindFragmentByTag("map") as MapFragment;
if (_mapFragment == null)
{
GoogleMapOptions mapOptions = new GoogleMapOptions()
.InvokeMapType(GoogleMap.MapTypeSatellite)
.InvokeZoomControlsEnabled(false)
.InvokeCompassEnabled(true);
A GoogleMap must be acquired using GetMapAsync , as shown at the end of the preceding code example – this
automatically initializes the Maps system and the view. (Note that this method does not use await / async
semantics – the Async behavior is implemented by Android.) When the GoogleMap object is ready, Android calls
your app's OnMapReady method (which you must implement as part of the IOnMapReadyCallback interface). For
example:
In the above code example, the OnMapReady callback initializes the _map variable to the created GoogleMap object.
As an example of how to use this result, when OnResume is called, it can check to see if _map is non-null. If _map is
set to a GoogleMap object, OnResume can call methods on it to add markers and move its camera to a specified
longitude and latitude. For a complete code example, see SimpleMapDemo.
Map Types
There are five different types of maps available from the Google Maps API:
Normal - This is the default map type. It shows roads and important natural features along with some man-
made points of interest (such as buildings and bridges).
Satellite - This map shows satellite photography.
Hybrid - This map shows satellite photography and road maps.
Terrain - This primarily shows topographical features with some roads.
None - This map does not load any tiles, it is rendered as an empty grid.
The image below shows three of the different types of of maps, from left-to-right (normal, hybrid, terrain):
The GoogleMap.MapType property is used to set or change which type of map is displayed. The following code
snippet shows how to display a satellite map.
GoogleMap Properties
GoogleMap defines several properties that can control the functionality and the appearance of the map. One way to
configure the initial state of a GoogleMap is to pass a GoogleMapOptions object when creating a MapFragment . The
following code snippet is one example of using a GoogleMapOptions object when creating a MapFragment :
The other way to configure a GoogleMap object is by setting values the UiSettings property of the map object. The
next code sample shows how to configure a GoogleMap to display the zoom controls and a compass:
This code snippet is a simple example of how to use the CameraUpdateFactory to create a CameraUpdate that will
increment the zoom level of the map by one:
The Maps API provides a CameraPosition which will aggregate all of the possible values for the camera position.
An instance of this class can be provided to the CameraUpdateFactory.NewCameraPosition method which will
return a CameraUpdate object. The Maps API also includes the CameraPosition.Builder class that provides a fluent
API for creating CameraPosition objects. The following code snippet shows an example of creating a CameraUpdate
from a CameraPosition and using that to change the camera position on a GoogleMap :
In the previous code snippet, a specific location on the map is represented by the a LatLng class. The zoom level is
set to 18. The bearing is the compass measurement clockwise from North. The Tilt property controls the viewing
angle and is specifies an angle of 25 degrees from the vertical. The following screenshot shows the GoogleMap after
executing the preceding code:
Drawing on the Map
The Android Maps API provides API's for drawing the following items on a map:
Markers - These are special icons that are used to identify a single location on a map.
Overlays - This is a image that can be used to identify a collection of locations or area on the map.
Lines, Polygons, and Circles - These are APIs that allow Activities to add shapes to a map.
Markers
The Maps API provides a Marker class which encapsulates all of the data about a single location on a map. By
default they use a standard icon provided by Google Maps. It is possible to customize the appearance of a marker
and to respond to user clicks.
A ddi n g a Mar ker
To add a marker to a map, it is necessary create a new MarkerOptions object and then call the AddMarker method
on a GoogleMap instance. This method will return a Marker object.
The title of the marker will be displayed in an info window when the user taps on the marker. The following
screenshot shows what this marker looks like:
C u st o m i z i n g A M a r k e r
It is possible to customize the icon used by the marker by calling the MarkerOptions.InvokeIcon method when
adding the marker to the map. This method takes a BitmapDescriptor object containing the data necessary to
render the icon. The BitmapDescriptorFactory class provides some helper methods to simplify the creation of a
BitmapDescriptor . The following list introduces some of these methods:
DefaultMarker(float colour) – Use the default Google Maps marker, but change the colour.
FromAsset(string assetName) – Use a custom icon from the specified file in the Assets folder.
FromBitmap(Bitmap image) – Use the specified bitmap as the icon.
FromFile(string fileName) – Create the custom icon from the file at the specified path.
FromResource(int resourceId) – Create a custom icon from the specified resource.
The following code snippet shows an example of creating a cyan coloured default marker:
mapFrag.GetMapAsync(this);
...
if (_map != null)
{
MarkerOptions markerOpt1 = new MarkerOptions();
markerOpt1.SetPosition(new LatLng(50.379444, 2.773611));
markerOpt1.SetTitle("Vimy Ridge");
markerOpt1.InvokeIcon(BitmapDescriptorFactory.DefaultMarker (BitmapDescriptorFactory.HueCyan));
_map.AddMarker(markerOpt1);
}
Info Windows
Info windows are special windows that popup to display information to the user when they tap a specific marker. By
default the info window will display the contents of the marker's title. If the title has not been assigned, then no info
window will appear. Only one info window may be shown at a time.
It is possible to customize the info window by implementing the GoogleMap.IInfoWindowAdapter interface. There
are two important methods on this interface:
public View GetInfoWindow(Marker marker) – This method is called to get a custom info window for a marker.
If it returns null , then the default window rendering will be used. If this method returns a View, then that
View will be placed inside the info window frame.
public View GetInfoContents(Marker marker) – This method will only be called if GetInfoWindow returns
null . This method can return a null value if the default rendering of the info window contents is to be
used. Otherwise, this method should return a View with the contents of the info window.
An info window is not a live view - instead Android will convert the View to a static bitmap and display that on the
image. This means that an info window cannot respond to any touch events or gestures, nor will it automatically
update itself. To update an info window, it is necessary to call the GoogleMap.ShowInfoWindow method.
The following image shows some examples of some customized info windows. The image on the left has it's
contents customized, while the image on the right has it's window and contents customized:
Ground Overlays
Unlike markers, which identify a specific location on a map, a GroundOverlay is an image that used to identify a
collection of locations or an area on the map.
A ddi n g a Gr o u n d O ver l ay
Adding a ground overlay to a map is very similar to adding a marker to a map. First, a GroundOverlayOptions
object is created. This object is then passed as a parameter to the GoogleMap.AddGroundOverlay method, which will
return a GroundOverlay object. This code snippet is an example of adding a ground overlay to a map:
BitmapDescriptor image = BitmapDescriptorFactory.FromResource(Resource.Drawable.polarbear);
GroundOverlayOptions groundOverlayOptions = new GroundOverlayOptions()
.Position(position, 150, 200)
.InvokeImage(image);
GroundOverlay myOverlay = _map.AddGroundOverlay(groundOverlayOptions);
A Polyline is a list of consecutive LatLng objects which specify the vertices of each line segment. A polyline is
created by first creating a PolylineOptions object and adding the points to it. The PolylineOption object is then
passed to a GoogleMap object by calling the AddPolyline method.
Polygons
Polygon s are very similar to Polyline s, however they are not open ended. Polygon s are a closed loop and have
their interior filled in. Polygon s are created in the exact same manner as a Polyline , except the
GoogleMap.AddPolygon method invoked.
Unlike a Polyline , a Polygon is self-closing. When AddPolygon is called, the method will automatically close off
the polygon by drawing a line which connects the first and last points. The following code snippet will create a solid
rectangle over the same area as the previous code snippet in the Polyline example.
Ci r c l es
Circles are created by first instantiating a CircleOption object which will specify the center and the radius of the
circle in metres. The circle is drawn on the map by calling GoogleMap.AddCircle. The following code snippet shows
how to draw a circle:
CircleOptions circleOptions = new CircleOptions ();
circleOptions.InvokeCenter (new LatLng(37.4, -122.1));
circleOptions.InvokeRadius (1000);
_map.AddCircle (circleOptions);
Responding To Events
There are three types of interactions a user may have with a map:
Marker Click - The user clicks on a marker.
Marker Drag - The user has long-clicked on a mparger
Info Window Click - The user has clicked on an info window.
Each of these events will be discussed in more detail below.
Marker Click Events
When the user clicks on a marker the MarkerClick event will be raised, and a GoogleMap.MarkerClickEventArgs
passed in. This class contains two properties:
GoogleMap.MarkerClickEventArgs.Handled – This property should be set to true to indicate that the event
handler has consumed the event. If this is set to false then the default behaviour will occur in addition to
the custom behaviour of the event handler.
P0 – This poorly name parameter is a reference to the marker that raised the MarkerClick event.
This code snippet shows an example of a MarkerClick that will change the camera position to a new location on
the map:
Recall that an info window is a static View which is rendered as an image on the map. Any widgets such as
buttons, check boxes, or text views that are placed inside the info window will be inert and cannot respond to any of
their integral user events.
Related Links
Google Play Services
Google Maps Android API v2
Google Play Services APK
Obtaining a Google Maps API key
Obtaining a Google Maps API Key
6/25/2018 • 6 minutes to read • Edit Online
To use the Google Maps functionality in Android, you need to register for a Maps API key with Google. Until you
do this, you will just see a blank grid instead of a map in your applications. You must obtain a Google Maps
Android API v2 key - keys from the older Google Maps Android API key v1 will not work.
Obtaining a Maps API v2 key involves the following steps:
1. Retrieve the SHA-1 fingerprint of the keystore that is used to sign the application.
2. Create a project in the Google APIs console.
3. Obtaining the API key.
keytool -list -v -keystore [STORE FILENAME] -alias [KEY NAME] -storepass [STORE PASSWORD] -keypass [KEY
PASSWORD]
Debug.keystore Example
For the default debug key (which is automatically created for you for debugging), use this command:
Visual Studio
Visual Studio for Mac
Production Keys
When deploying an app to Google Play, it must be signed with a private key. The keytool will need to be run with
the private key details, and the resulting SHA-1 fingerprint used to create a production Google Maps API key.
Remember to update the AndroidManifest.xml file with the correct Google Maps API key before deployment.
Keytool Output
You should see something like the following output in your console window:
You will use the SHA-1 fingerprint (listed after SHA1) later in this guide.
2. If you created a new project, enter the project name in the New Project dialog that is displayed. This
dialog will manufacture a unique project ID that is based on your project name. Next, click the Create
button as shown in this example:
3. After a minute or so, the project is created and you are taken to the Dashboard page of the project. From
there, click ENABLE APIS AND SERVICES:
4. From the API Library page, click Maps SDK for Android. On the next page, click ENABLE to turn on the
service for this project:
At this point the API project has been created and Google Maps Android API v2 has been added to it. However,
you cannot use this API in your project until you create credentials for it. The next section explains how to create
an API key and white-list a Xamarin.Android application so that it is authorized to use this key.
3. After this button is clicked, the API key is generated. Next it is necessary to restrict this key so that only
your app can call APIs with this key. Click RESTRICT KEY:
4. Change the Name field from API Key 1 to a name that will help you remember what the key is used for
(XamarinMapsDemoKey is used in this example). Next, click the Android apps radio button:
5. To add the SHA-1 fingerprint, click + Add package name and fingerprint:
6. Enter your app's package name and enter the SHA-1 certificate fingerprint (obtained via keytool as
explained earlier in this guide). In the following example, the package name for XamarinMapsDemo is entered,
followed by the SHA-1 certificate fingerprint obtained from debug.keystore:
7. Note that, in order for your APK to access Google Maps, you must include SHA-1 fingerprints and package
names for every keystore (debug and release) that you use to sign your APK. For example, if you use one
computer for debug and another computer for generating the release APK, you should include the SHA-1
certificate fingerprint from the debug keystore of the first computer and the SHA-1 certificate fingerprint
from the release keystore of the second computer. Click + Add package name and fingerprint to add
another fingerprint and package name as shown in this example:
8. Click the Save button to save your changes. Next, you are returned to the list of your API keys. If you have
other API keys that you have created earlier, they will also be listed here. In this example, only one API key
(created in the previous steps) is listed:
Connect the project to a billable account
Beginning June,11 2018, the API key will not work if the project is not connected to a billable account (even if the
service is still free for mobile apps).
1. Click the hamburger menu button and select the Billing page:
2. Link the project to a billing account by clicking Link a billing account followed by CREATE BILLING
ACCOUNT on the displayed popup (if you don't have an account, you will be guided to create a new one):
Adding the Key to Your Project
Finally, add this API key to the AndroidManifest.XML file of your Xamarin.Android app. In the following
example, YOUR_API_KEY is to be replaced with the API key generated in the previous steps:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionName="4.10" package="com.xamarin.docs.android.mapsandlocationdemo"
android:versionCode="10">
...
<application android:label="@string/app_name">
<!-- Put your Google Maps V2 API Key here. -->
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="YOUR_API_KEY" />
<meta-data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
</application>
</manifest>
Related Links
Google APIs Console
The Google Maps API Key
keytool
Android Speech
4/12/2018 • 8 minutes to read • Edit Online
This article covers the basics of using the very powerful Android.Speech namespace. Since its inception, Android
has been able to recognize speech and output it as text. It is a relatively simple process. For text to speech, however,
the process is more involved, as not only does the speech engine have to be taken into account, but also the
languages available and installed from the Text To Speech (TTS ) system.
Speech Overview
Having a system, which "understands" human speech and enunciates what is being typed—Speech to Text, and
Text to Speech—is an ever growing area within mobile development as the demand for natural communication
with our devices rises. There are many instances where having a feature that converts text into speech, or vice
versa, is a very useful tool to incorporate into your android application.
For example, with the clamp down on mobile phone use while driving, users want a hands free way of operating
their devices. The plethora of different Android form factors—such as Android Wear—and the ever-widening
inclusion of those able to use Android devices (such as tablets and note pads), has created a larger focus on great
TTS applications.
Google supplies the developer with a rich set of APIs in the Android.Speech namespace to cover most instances of
making a device "speech aware" (such as software designed for the blind). The namespace includes the facility to
allow text to be translated into speech through Android.Speech.Tts , control over the engine used to perform the
translation, as well as a number of RecognizerIntent s which allow speech to be converted to text.
While the facilities are there for speech to be understood, there are limitations based on the hardware used. It is
unlikely that the device will successfully interpret everything spoken to it in every language available.
Requirements
There are no special requirements for this guide, other than your device having a microphone and speaker.
The core of an Android device interpreting speech is the use of an Intent with a corresponding OnActivityResult .
It is important, though, to recognize that the speech is not understood—but interpreted to text. The difference is
important.
The difference between understanding and interpreting
A simple definition of understanding is that you are able to determine by tone and context the real meaning of
what is being said. To interpret just means to take the words and output them in another form.
Consider the following simple example that is used in everyday conversation:
Hello, how are you?
Without inflection (emphasis placed on specific words or parts of words), it is a simple question. However, if a slow
pace is applied to the line, the person listening will detect that the asker is not too happy and perhaps needs
cheering up or that the asker is unwell. If the emphasis is placed on "are", the person asking is usually more
interested in the response.
Without fairly powerful audio processing to make use of the inflection, and a degree of artificial intelligence (AI) to
understand the context, the software cannot even begin to understand what was said—the best a simple phone can
do is convert the speech to text.
Setting up
Before using the speech system, it is always wise to check to ensure the device has a microphone. There would be
little point trying to run your app on a Kindle or Google note pad without a microphone installed.
The code sample below demonstrates querying if a microphone is available and if not, to create an alert. If no
microphone is available at this point you would either quit the activity or disable the ability to record the speech.
Text to Speech
Text to speech is not quite the reverse of speech to text and relies on two key components; a text-to-speech engine
being installed on the device and a language being installed.
Largely, Android devices come with the default Google TTS service installed and at least one language. This is
established when the device is first set up and will be based on where the device is at the time (for example, a
phone set up in Germany will install the German language, whereas one in America will have American English).
Step 1 - Instantiating TextToSpeech
TextToSpeech can take up to 3 parameters, the first two are required with the third being optional ( AppContext ,
IOnInitListener , engine ). The listener is used to bind to the service and test for failure with the engine being any
number of available Android text to speech engines. At a minimum, the device will have Google’s own engine.
Step 2 - Finding the languages available
The Java.Util.Locale class contains a helpful method called GetAvailableLocales() . This list of languages
supported by the speech engine can then be tested against the installed languages.
It is a trivial matter to generate the list of "understood" languages. There will always be a default language (the
language the user set when they first set their device up), so in this example the List<string> has "Default" as the
first parameter, the remainder of the list will be filled depending on the result of the
textToSpeech.IsLanguageAvailable(locale) .
var langAvailable = new List<string>{ "Default" };
var localesAvailable = Java.Util.Locale.GetAvailableLocales().ToList();
foreach (var locale in localesAvailable)
{
var res = textToSpeech.IsLanguageAvailable(locale);
switch (res)
{
case LanguageAvailableResult.Available:
langAvailable.Add(locale.DisplayLanguage);
break;
case LanguageAvailableResult.CountryAvailable:
langAvailable.Add(locale.DisplayLanguage);
break;
case LanguageAvailableResult.CountryVarAvailable:
langAvailable.Add(locale.DisplayLanguage);
break;
}
}
langAvailable = langAvailable.OrderBy(t => t).Distinct().ToList();
This code calls TextToSpeech.IsLanguageAvailable to test if the language package for a given locale is already
present on the device. This method returns a LanguageAvailableResult, which indicates whether the language for
the passed locale is available. If LanguageAvailableResult indicates that the language is NotSupported , then there is
no voice package available (even for download) for that language. If LanguageAvailableResult is set to MissingData
, then it is possible to download a new language package as explained below in Step 4.
Step 3 - Setting the speed and pitch
Android allows the user to alter the sound of the speech by altering the SpeechRate and Pitch (the rate of speed
and the tone of the speech). This goes from 0 to 1, with "normal" speech being 1 for both.
Step 4 - Testing and loading new languages
Downloading a new language is performed by using an Intent . The result of this intent causes the
OnActivityResult method to be invoked. Unlike the speech-to-text example (which used the RecognizerIntent as a
PutExtra parameter to the Intent ), the testing and loading Intent s are Action -based:
As an example, the user might pick French and click the download icon to download French voice data:
Summary
In this guide we have looked at the basics of converting text to speech and speech to text and possible methods of
how to include them within your own apps. While they do not cover every particular case, you should now have a
basic understanding of how speech is interpreted, how to install new languages, and how to increase the inclusivity
of your apps.
Related Links
Xamarin.Forms DependencyService
Text to Speech (sample)
Speech to Text (sample)
Android.Speech namespace
Android.Speech.Tts namespace
Java Integration Overview
4/12/2018 • 2 minutes to read • Edit Online
The Java ecosystem includes a diverse and immense collection of components. Many of these components can be
used to reduce the time it takes to develop an Android application. This document will introduce and provide a
high-level overview of some of the ways that developers can use these existing Java components to improve their
Xamarin.Android application development experience.
Overview
Given the extent of the Java ecosystem, it is very likely that any given functionality required for a Xamarin.Android
application has already been coded in Java. Because of this, it is appealing to try and reuse these existing libraries
when creating a Xamarin.Android application.
There are three possible ways to reuse Java libraries in a Xamarin.Android application:
Create a Java Bindings Library – With this technique, a Xamarin.Android project is used to create C#
wrappers around the Java types. A Xamarin.Android application can then reference the C# wrappers
created by this project, and then use the .jar file.
Java Native Interface – The Java Native Interface (JNI) is a framework that allows non-Java code (such
as C++ or C#) to call or be called by Java code running inside a JVM.
Port the Code – This method involves taking the Java source code, and then converting it to C#. This can
be done manually, or by using an automated tool such as Sharpen.
At the core of the first two techniques is the Java Native Interface (JNI). JNI is a framework that allows
applications not written in Java to interact with Java code running in a Java Virtual Machine. Xamarin.Android
uses JNI to create bindings for C# code.
The first technique is a more automated, declarative approach to binding Java libraries. It involves using either
Visual Studio for Mac or a Visual Studio project type that is provided by Xamarin.Android – the Java Bindings
Library. To successfully create these bindings, a Java Bindings Library may still require some manual
modifications, but not as many as would a pure JNI approach. See Binding a Java Library for more information
about Java Binding libraries.
The second technique, using JNI, works at a much lower level, but can provide for finer control and access to Java
methods that would not normally be accessible through a Java Binding Library.
The third technique is radically different from the previous two: porting the code from Java to C#. Porting code
from one language to another can be a very laborious process, but it is possible to reduce that effort with the help
of a tool called Sharpen. Sharpen is an open source tool that is a Java-to-C# converter.
Summary
This document provided a high-level overview of some of the different ways that libraries from Java can be
reused in a Xamarin.Android application. It introduced the concepts of bindings and managed callable wrappers,
and discussed options for porting Java code to C#.
Related Links
Architecture
Binding a Java Library
Working with JNI
Sharpen
Java Native Interface
Android Callable Wrappers
4/12/2018 • 3 minutes to read • Edit Online
Android Callable Wrappers (ACWs) are required whenever the Android runtime invokes managed code. These
wrappers are required because there is no way to register classes with ART (the Android runtime) at runtime.
(Specifically, the JNI DefineClass() function is not supported by the Android runtime.} Android Callable Wrappers
thus make up for the lack of runtime type registration support.
Every time Android code needs to execute a virtual or interface method that is overridden or implemented in
managed code, Xamarin.Android must provide a Java proxy so that this method is dispatched to the appropriate
managed type. These Java proxy types are Java code that has the "same" base class and Java interface list as the
managed type, implementing the same constructors and declaring any overridden base class and interface
methods.
Android callable wrappers are generated by the monodroid.exe program during the build process: they are
generated for all types that (directly or indirectly) inherit Java.Lang.Object.
Also, you may see errors like the following if you attempt to reference a type by name:
If you do require access to types by name, you can declare a name for that type in an attribute declaration. For
example, here is code that declares an activity with the fully-qualified name My.ActivityType :
namespace My {
[Activity]
public partial class ActivityType : Activity {
/* ... */
}
}
The ActivityAttribute.Name property can be set to explicitly declare the name of this activity:
namespace My {
[Activity(Name="my.ActivityType")]
public partial class ActivityType : Activity {
/* ... */
}
}
After this property setting is added, my.ActivityType can be accessed by name from external code and from adb
scripts. The Name attribute can be set for many different types including Activity , Application , Service ,
BroadcastReceiver , and ContentProvider :
ActivityAttribute.Name
ApplicationAttribute.Name
ServiceAttribute.Name
BroadcastReceiverAttribute.Name
ContentProviderAttribute.Name
MD5SUM -based ACW naming was introduced in Xamarin.Android 5.0. For more information about attribute
naming, see RegisterAttribute.
Implementing Interfaces
There are times when you may need to implement an Android interface, such as
Android.Content.IComponentCallbacks. Since all Android classes and interface extend the
Android.Runtime.IJavaObject interface, the question arises: how do we implement IJavaObject ?
The question was answered above: the reason all Android types need to implement IJavaObject is so that
Xamarin.Android has an Android callable wrapper to provide to Android, i.e. a Java proxy for the given type. Since
monodroid.exe only looks for Java.Lang.Object subclasses, and Java.Lang.Object implements IJavaObject,
the answer is obvious: subclass Java.Lang.Object :
Implementation Details
The remainder of this page provides implementation details subject to change without notice (and is presented
here only because developers will be curious about what's going on).
For example, given the following C# source:
using System;
using Android.App;
using Android.OS;
namespace Mono.Samples.HelloWorld
{
public class HelloAndroid : Activity
{
protected override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
SetContentView (R.layout.main);
}
}
}
The mandroid.exe program will generate the following Android Callable Wrapper:
package mono.samples.helloWorld;
public HelloAndroid ()
{
super ();
if (getClass () == HelloAndroid.class)
mono.android.TypeManager.Activate (
"Mono.Samples.HelloWorld.HelloAndroid, HelloWorld, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null", "", this, new java.lang.Object[] { });
}
@Override
public void onCreate (android.os.Bundle p0)
{
n_onCreate (p0);
}
Notice that the base class is preserved, and native method declarations are provided for each method that is
overridden within managed code.
Working With JNI
4/12/2018 • 46 minutes to read • Edit Online
Xamarin.Android permits writing Android apps within C# instead of Java. Several assemblies are provided with
Xamarin.Android which provide bindings for Java libraries, including Mono.Android.dll and
Mono.Android.GoogleMaps.dll. However, bindings are not provided for every possible Java library, and the
bindings that are provided may not bind every Java type and member. To use unbound Java types and members,
the Java Native Interface (JNI ) may be used. This article illustrates how to use JNI to interact with Java types and
members from Xamarin.Android applications.
Overview
It is not always necessary or possible to create a Managed Callable Wrapper (MCW ) to invoke Java code. In many
cases, "inline" JNI is perfectly acceptable and useful for one-off use of unbound Java members. It is often simpler
to use JNI to invoke a single method on a Java class than to generate an entire .jar binding.
Xamarin.Android provides the Mono.Android.dll assembly, which provides a binding for Android's android.jar
library. Types and members not present within Mono.Android.dll and types not present within android.jar may
be used by manually binding them. To bind Java types and members, you use the Java Native Interface (JNI ) to
lookup types, read and write fields, and invoke methods.
The JNI API in Xamarin.Android is conceptually very similar to the System.Reflection API in .NET: it makes it
possible for you to look up types and members by name, read and write field values, invoke methods, and more.
You can use JNI and the Android.Runtime.RegisterAttribute custom attribute to declare virtual methods that can
be bound to support overriding. You can bind interfaces so that they can be implemented in C#.
This document explains:
How JNI refers to types.
How to lookup, read, and write fields.
How to lookup and invoke methods.
How to expose virtual methods to allow overriding from managed code.
How to expose interfaces.
Requirements
JNI, as exposed through the Android.Runtime.JNIEnv namespace, is available in every version of
Xamarin.Android. To bind Java types and interfaces, you must use Xamarin.Android 4.0 or later.
Implementation Details
The remainder of this article provides implementation details subject to change without notice (and is presented
here only because developers may be curious about what's going on under the hood).
For example, given the following C# source:
using System;
using Android.App;
using Android.OS;
namespace Mono.Samples.HelloWorld
{
public class HelloAndroid : Activity
{
protected override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
SetContentView (R.layout.main);
}
}
}
The mandroid.exe program will generate the following Android Callable Wrapper:
package mono.samples.helloWorld;
public HelloAndroid ()
{
super ();
if (getClass () == HelloAndroid.class)
mono.android.TypeManager.Activate (
"Mono.Samples.HelloWorld.HelloAndroid, HelloWorld, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null",
"", this, new java.lang.Object[] { });
}
@Override
public void onCreate (android.os.Bundle p0)
{
n_onCreate (p0);
}
Notice that the base class is preserved, and native method declarations are provided for each method that is
overridden within managed code.
ExportAttribute and ExportFieldAttribute
Typically, Xamarin.Android automatically generates the Java code that comprises the ACW; this generation is
based on the class and method names when a class derives from a Java class and overrides existing Java
methods. However, in some scenarios, the code generation is not adequate, as outlined below:
Android supports action names in layout XML attributes, for example the android:onClick XML attribute.
When it is specified, the inflated View instance tries to look up the Java method.
The java.io.Serializable interface requires readObject and writeObject methods. Since they are not
members of this interface, our corresponding managed implementation does not expose these methods to
Java code.
The android.os.Parcelable interface expects that an implementation class must have a static field CREATOR
of type Parcelable.Creator . The generated Java code requires some explicit field. With our standard
scenario, there is no way to output field in Java code from managed code.
Because code generation does not provide a solution to generate arbitrary Java methods with arbitrary names,
starting with Xamarin.Android 4.2, the ExportAttribute and ExportFieldAttribute were introduced to offer a
solution to the above scenarios. Both attributes reside in the Java.Interop namespace:
ExportAttribute – specifies a method name and its expected exception types (to give explicit "throws" in
Java). When it is used on a method, the method will "export" a Java method that generates a dispatch code
to the corresponding JNI invocation to the managed method. This can be used with android:onClick and
java.io.Serializable .
ExportFieldAttribute– specifies a field name. It resides on a method that works as a field initializer. This
can be used with android.os.Parcelable .
The ExportAttribute sample project illustrates how to use these attributes.
Troubleshooting ExportAttribute and ExportFieldAttribute
Packaging fails due to missing Mono.Android.Export.dll – if you used ExportAttribute or
ExportFieldAttribute on some methods in your code or dependent libraries, you have to add
Mono.Android.Export.dll. This assembly is isolated to support callback code from Java. It is separate
from Mono.Android.dll as it adds additional size to the application.
In Release build, MissingMethodException occurs for Export methods – In Release build,
MissingMethodException occurs for Export methods. (This issue is fixed in the latest version of
Xamarin.Android.)
ExportParameterAttribute
ExportAttribute and ExportFieldAttribute provide functionality that Java run-time code can use. This run-time
code accesses managed code through the generated JNI methods driven by those attributes. As a result, there is
no existing Java method that the managed method binds; hence, the Java method is generated from a managed
method signature.
However, this case is not fully determinant. Most notably, this is true in some advanced mappings between
managed types and Java types such as:
InputStream
OutputStream
XmlPullParser
XmlResourceParser
When types such as these are needed for exported methods, the ExportParameterAttribute must be used to
explicitly give the corresponding parameter or return value a type.
Annotation Attribute
In Xamarin.Android 4.2, we converted IAnnotation implementation types into attributes (System.Attribute), and
added support for annotation generation in Java wrappers.
This means the following directional changes:
The binding generator generates Java.Lang.DeprecatedAttribute from java.Lang.Deprecated (while it
should be [Obsolete] in managed code).
This does not mean that existing Java.Lang.Deprecated class will vanish. These Java-based objects could be
still used as usual Java objects (if such usage exists). There will be Deprecated and DeprecatedAttribute
classes.
The Java.Lang.DeprecatedAttribute class is marked as [Annotation] . When there is a custom attribute
that is inherited from this [Annotation] attribute, msbuild task will generate a Java annotation for that
custom attribute (@Deprecated) in the Android Callable Wrapper (ACW ).
Annotations could be generated onto classes, methods and exported fields (which is a method in managed
code).
If the containing class (the annotated class itself, or the class that contains the annotated members) is not
registered, the entire Java class source is not generated at all, including annotations. For methods, you can specify
the ExportAttribute to get the method explicitly generated and annotated. Also, it is not a feature to "generate" a
Java annotation class definition. In other words, if you define a custom managed attribute for a certain annotation,
you'll have to add another .jar library that contains the corresponding Java annotation class. Adding a Java source
file that defines the annotation type is not sufficient. The Java compiler does not work in the same way as apt.
Additionally the following limitations apply:
This conversion process does not consider @Target annotation on the annotation type so far.
Attributes onto a property does not work. Use attributes for property getter or setter instead.
Class Binding
Binding a class means writing a managed callable wrapper to simplify invocation of the underlying Java type.
Binding virtual and abstract methods to permit overriding from C# requires Xamarin.Android 4.0. However, any
version of Xamarin.Android can bind non-virtual methods, static methods, or virtual methods without supporting
overrides.
A binding typically contains the following items:
A JNI handle to the Java type being bound.
JNI field IDs and properties for each bound field.
JNI method IDs and methods for each bound method.
If sub-classing is required, the type needs to have a RegisterAttribute custom attribute on the type
declaration with RegisterAttribute.DoNotGenerateAcw set to true .
Declaring Type Handle
The field and method lookup methods require an object reference referring to their declaring type. By convention,
this is held in a class_ref field:
See the JNI Type References section for details about the CLASS token.
Binding Fields
Java fields are exposed as C# properties, for example the Java field java.lang.System.in is bound as the C#
property Java.Lang.JavaSystem.In. Furthermore, since JNI distinguishes between static fields and instance fields,
different methods be used when implementing the properties.
Field binding involves three sets of methods:
1. The get field id method. The get field id method is responsible for returning a field handle that the get field
value and set field value methods will use. Obtaining the field id requires knowing the declaring type, the
name of the field, and the JNI type signature of the field.
2. The get field value methods. These methods require the field handle and are responsible for reading the
field's value from Java. The method to use depends upon the field's type.
3. The set field value methods. These methods require the field handle and are responsible for writing the
field's value within Java. The method to use depends upon the field's type.
Static fields use the JNIEnv.GetStaticFieldID, JNIEnv.GetStatic*Field , and JNIEnv.SetStaticField methods.
Instance fields use the JNIEnv.GetFieldID, JNIEnv.Get*Field , and JNIEnv.SetField methods.
For example, the static property JavaSystem.In can be implemented as:
Note: We're using InputStreamInvoker.FromJniHandle to convert the JNI reference into a System.IO.Stream
instance, and we're using JniHandleOwnership.TransferLocalRef because JNIEnv.GetStaticObjectField returns a
local reference.
Many of the Android.Runtime types have FromJniHandle methods which will convert a JNI reference into the
desired type.
Method Binding
Java methods are exposed as C# methods and as C# properties. For example, the Java method
java.lang.Runtime.runFinalizersOnExit method is bound as the Java.Lang.Runtime.RunFinalizersOnExit method,
and the java.lang.Object.getClass method is bound as the Java.Lang.Object.Class property.
Method invocation is a two-step process:
1. The get method id for the method to invoke. The get method id method is responsible for returning a
method handle that the method invocation methods will use. Obtaining the method id requires knowing
the declaring type, the name of the method, and the JNI type signature of the method.
2. Invoke the method.
Just as with fields, the methods to use to get the method id and invoke the method differ between static methods
and instance methods.
Static methods use JNIEnv.GetStaticMethodID () to lookup the method id, and use the JNIEnv.CallStatic*Method
family of methods for invocation.
Instance methods use JNIEnv.GetMethodID to lookup the method id, and use the JNIEnv.Call*Method and
JNIEnv.CallNonvirtual*Method families of methods for invocation.
Method binding is potentially more than just method invocation. Method binding also includes allowing a method
to be overridden (for abstract and non-final methods) or implemented (for interface methods). The Supporting
Inheritance, Interfaces section covers the complexities of supporting virtual methods and interface methods.
Static Methods
Binding a static method involves using JNIEnv.GetStaticMethodID to obtain a method handle, then using the
appropriate JNIEnv.CallStatic*Method method, depending on the method's return type. The following is an
example of a binding for the Runtime.getRuntime method:
return Java.Lang.Object.GetObject<Java.Lang.Runtime> (
JNIEnv.CallStaticObjectMethod (class_ref, id_getRuntime),
JniHandleOwnership.TransferLocalRef);
}
Note that we store the method handle in a static field, id_getRuntime . This is a performance optimization, so that
the method handle doesn't need to be looked up on every invocation. It is not necessary to cache the method
handle in this way. Once the method handle is obtained, JNIEnv.CallStaticObjectMethod is used to invoke the
method. JNIEnv.CallStaticObjectMethod returns an IntPtr which contains the handle of the returned Java
instance. Java.Lang.Object.GetObject<T>(IntPtr, JniHandleOwnership) is used to convert the Java handle into a
strongly typed object instance.
Non-virtual Instance Method Binding
Binding a instance method, or an instance method which doesn't require overriding, involves using
final
JNIEnv.GetMethodID to obtain a method handle, then using the appropriate JNIEnv.Call*Method method,
depending on the method's return type. The following is an example of a binding for the Object.Class property:
Note that we store the method handle in a static field, id_getClass . This is a performance optimization, so that
the method handle doesn't need to be looked up on every invocation. It is not necessary to cache the method
handle in this way. Once the method handle is obtained, JNIEnv.CallStaticObjectMethod is used to invoke the
method. JNIEnv.CallStaticObjectMethod returns an IntPtr which contains the handle of the returned Java
instance. Java.Lang.Object.GetObject<T>(IntPtr, JniHandleOwnership) is used to convert the Java handle into a
strongly typed object instance.
Binding Constructors
Constructors are Java methods with the name "<init>" . Just as with Java instance methods, JNIEnv.GetMethodID
is used to lookup the constructor handle. Unlike Java methods, the JNIEnv.NewObject methods are used to
invoke the constructor method handle. The return value of JNIEnv.NewObject is a JNI local reference:
int value = 42;
IntPtr class_ref = JNIEnv.FindClass ("java/lang/Integer");
IntPtr id_ctor_I = JNIEnv.GetMethodID (class_ref, "<init>", "(I)V");
IntPtr lrefInstance = JNIEnv.NewObject (class_ref, id_ctor_I, new JValue (value));
// Dispose of lrefInstance, class_ref…
Normally a class binding will subclass Java.Lang.Object. When subclassing Java.Lang.Object , an additional
semantic comes into play: a Java.Lang.Object instance maintains a global reference to a Java instance through
the Java.Lang.Object.Handle property.
1. The Java.Lang.Object default constructor will allocate a Java instance.
2. If the type has a RegisterAttribute , and RegisterAttribute.DoNotGenerateAcw is true , then an instance of
the RegisterAttribute.Name type is created through its default constructor.
3. Otherwise, the Android Callable Wrapper (ACW ) corresponding to this.GetType is instantiated through
its default constructor. Android Callable Wrappers are generated during package creation for every
Java.Lang.Object subclass for which RegisterAttribute.DoNotGenerateAcw is not set to true .
For types which are not class bindings, this is the expected semantic: instantiating a
Mono.Samples.HelloWorld.HelloAndroid C# instance should construct a Java mono.samples.helloworld.HelloAndroid
instance which is a generated Android Callable Wrapper.
For class bindings, this may be the correct behavior if the Java type contains a default constructor and/or no other
constructor needs to be invoked. Otherwise, a constructor must be provided which performs the following
actions:
1. Invoking the Java.Lang.Object(IntPtr, JniHandleOwnership) instead of the default Java.Lang.Object
constructor. This is needed to avoid creating a new Java instance.
2. Check the value of Java.Lang.Object.Handle before creating any Java instances. The Object.Handle
property will have a value other than IntPtr.Zero if an Android Callable Wrapper was constructed in Java
code, and the class binding is being constructed to contain the created Android Callable Wrapper instance.
For example, when Android creates a mono.samples.helloworld.HelloAndroid instance, the the Android
Callable Wrapper will be created first , and the Java HelloAndroid constructor will create an instance of the
corresponding Mono.Samples.HelloWorld.HelloAndroid type, with the Object.Handle property being set to
the Java instance prior to constructor execution.
3. If the current runtime type is not the same as the declaring type, then an instance of the corresponding
Android Callable Wrapper must be created, and use Object.SetHandle to store the handle returned by
JNIEnv.CreateInstance.
4. If the current runtime type is the same as the declaring type, then invoke the Java constructor and use
Object.SetHandle to store the handle returned by JNIEnv.NewInstance .
For example, consider the java.lang.Integer(int) constructor. This is bound as:
// Cache the constructor's method handle for later use
static IntPtr id_ctor_I;
package mono.android.test;
public class Adder {
public int add (int a, int b) {
return a + b;
}
}
The Adder type could be bound as:
public Adder ()
{
}
Here, the Adder C# type aliases the Adder Java type. The [Register] attribute is used to specify the JNI name of
the mono.android.test.Adder Java type, and the DoNotGenerateAcw property is used to inhibit ACW generation.
This will result in the generation of an ACW for the ManagedAdder type, which properly subclasses the
mono.android.test.Adder type. If the RegisterAttribute.DoNotGenerateAcw property hadn't been used, then the
Xamarin.Android build process would have generated a new mono.android.test.Adder Java type. This would
result in compilation errors, as the mono.android.test.Adder type would be present twice, in two separate files.
Binding Virtual Methods
ManagedAdder subclasses the Java Adder type, but it isn't particularly interesting: the C# Adder type doesn't
define any virtual methods, so ManagedAdder can't override anything.
Binding virtual methods to permit overriding by subclasses requires several things that need to be done which
fall into the following two categories:
1. Method Binding
2. Method Registration
Method Binding
A method binding requires the addition of two support members to the C# Adder definition: ThresholdType , and
ThresholdClass .
T h r e sh o l d T y p e
ThresholdType is used in the Method Binding to determine when it should perform virtual vs. non-virtual method
dispatch. It should always return a System.Type instance which corresponds to the declaring C# type.
T h r e sh o l d C l a ss
The ThresholdClass property returns the JNI class reference for the bound type:
partial class Adder {
protected override IntPtr ThresholdClass {
get {
return class_ref;
}
}
}
The id_add field contains the method ID for the Java method to invoke. The id_add value is obtained from
JNIEnv.GetMethodID , which requires the declaring class ( class_ref ), the Java method name ( "add" ), and the JNI
signature of the method ( "(II)I" ).
Once the method ID is obtained, GetType is compared to ThresholdType to determine if virtual or non-virtual
dispatch is required. Virtual dispatch is required when GetType matches ThresholdType , as Handle may refer to a
Java-allocated subclass which overrides the method.
When GetType doesn't match ThresholdType , Adder has been subclassed (e.g. by ManagedAdder ), and the
Adder.Add implementation will only be invoked if the subclass invoked base.Add . This is the non-virtual dispatch
case, which is where ThresholdClass comes in. ThresholdClass specifies which Java class will provide the
implementation of the method to invoke.
Method Registration
Assume we have an updated ManagedAdder definition which overrides the Adder.Add method:
The first two parameters allow the ACW generation process to generate a method declaration to override the
method. The resulting ACW would contain some of the following code:
Note that an @Override method is declared, which delegates to an n_ -prefixed method of the same name. This
ensure that when Java code invokes ManagedAdder.add , ManagedAdder.n_add will be invoked, which will allow the
overriding C# ManagedAdder.Add method to be executed.
Thus, the most important question: how is ManagedAdder.n_add hooked up to ManagedAdder.Add ?
Java native methods are registered with the Java (the Android runtime) runtime through the JNI
RegisterNatives function. RegisterNatives takes an array of structures containing the Java method name, the JNI
Type Signature, and a function pointer to invoke that follows JNI calling convention. The function pointer must be
a function that takes two pointer arguments followed by the method parameters. The Java ManagedAdder.n_add
method must be implemented through a function that has the following C prototype:
Xamarin.Android does not expose a RegisterNatives method. Instead, the ACW and the MCW together provide
the information necessary to invoke RegisterNatives : the ACW contains the method name and the JNI type
signature, the only thing missing is a function pointer to hook up.
This is where the connector method comes in. The third [Register] custom attribute parameter is the name of a
method defined in the registered type or a base class of the registered type that accepts no parameters and
returns a System.Delegate . The returned System.Delegate in turn refers to a method that has the correct JNI
function signature. Finally, the delegate that the connector method returns must be rooted so that the GC doesn't
collect it, as the delegate is being provided to Java.
#pragma warning disable 0169
static Delegate cb_add;
// This method must match the third parameter of the [Register]
// custom attribute, must be static, must return System.Delegate,
// and must accept no parameters.
static Delegate GetAddHandler ()
{
if (cb_add == null)
cb_add = JNINativeWrapper.CreateDelegate ((Func<IntPtr, IntPtr, int, int, int>) n_Add);
return cb_add;
}
// This method is registered with JNI.
static int n_Add (IntPtr jnienv, IntPtr lrefThis, int a, int b)
{
Adder __this = Java.Lang.Object.GetObject<Adder>(lrefThis, JniHandleOwnership.DoNotTransfer);
return __this.Add (a, b);
}
#pragma warning restore 0169
The GetAddHandler method creates a Func<IntPtr, IntPtr, int, int, int> delegate which refers to the n_Add
method, then invokes JNINativeWrapper.CreateDelegate. JNINativeWrapper.CreateDelegate wraps the provided
method in a try/catch block, so that any unhandled exceptions are handled and will result in raising the
AndroidEvent.UnhandledExceptionRaiser event. The resulting delegate is stored in the static cb_add variable so
that the GC will not free the delegate.
Finally, the n_Add method is responsible for marshaling the JNI parameters to the corresponding managed types,
then delegating the method call.
Note: Always use JniHandleOwnership.DoNotTransfer when obtaining an MCW over a Java instance. Treating them
as a local reference (and thus calling JNIEnv.DeleteLocalRef ) will break managed -> Java -> managed stack
transitions.
Complete Adder Binding
The complete managed binding for the mono.android.tests.Adder type is:
[Register ("mono/android/test/Adder", DoNotGenerateAcw=true)]
public class Adder : Java.Lang.Object {
public Adder ()
{
}
#region Add
static IntPtr id_add;
Restrictions
When writing a type that matches the following criteria:
1. Subclasses Java.Lang.Object
Then for GC interaction the type must not have any fields which may refer to a Java.Lang.Object or
Java.Lang.Object subclass at runtime. For example, fields of type System.Object and any interface type are not
permitted. Types which cannot refer to Java.Lang.Object instances are permitted, such as System.String and
List<int> . This restriction is to prevent premature object collection by the GC.
If the type must contain an instance field that can refer to a Java.Lang.Object instance, then the field type must be
System.WeakReference or GCHandle .
The Invoker type is only necessary when obtaining JNI references to Java-created instances.
Binding Interfaces
Binding interfaces is conceptually similar to binding classes containing virtual methods, but many of the specifics
differ in subtle (and not so subtle) ways. Consider the following Java interface declaration:
Interface bindings have two parts: the C# interface definition, and an Invoker definition for the interface.
Interface Definition
The C# interface definition must fulfill the following requirements:
The interface definition must have a [Register] custom attribute.
The interface definition must extend the IJavaObject interface . Failure to do so will prevent ACWs from
inheriting from the Java interface.
Each interface method must contain a [Register] attribute specifying the corresponding Java method
name, the JNI signature, and the connector method.
The connector method must also specify the type that the connector method can be located on.
When binding abstract and virtual methods, the connector method would be searched within the inheritance
hierarchy of the type being registered. Interfaces can have no methods containing bodies, so this doesn't work,
thus the requirement that a type be specified indicating where the connector method is located. The type is
specified within the connector method string, after a colon ':' , and must be the assembly qualified type name of
the type containing the invoker.
Interface method declarations are a translation of the corresponding Java method using compatible types. For
Java builtin types, the compatible types are the corresponding C# types, e.g. Java int is C# int . For reference
types, the compatible type is a type that can provide a JNI handle of the appropriate Java type.
The interface members will not be directly invoked by Java – invocation will be mediated through the Invoker
type – so some amount of flexibility is permitted.
The Java Progress interface can be declared in C# as:
Notice in the above that we map the Java int[] parameter to a JavaArray<int>. This isn't necessary: we could
have bound it to a C# int[] , or an IList<int> , or something else entirely. Whatever type is chosen, the Invoker
needs to be able to translate it into a Java int[] type for invocation.
Invoker Definition
The Invoker type definition must inherit Java.Lang.Object , implement the appropriate interface, and provide all
connection methods referenced in the interface definition. There is one more suggestion that differs from a class
binding: the class_ref field and method IDs should be instance members, not static members.
The reason for preferring instance members has to do with JNIEnv.GetMethodID behavior in the Android runtime.
(This may be Java behavior as well; it hasn't been tested.) JNIEnv.GetMethodID returns null when looking up a
method that comes from an implemented interface and not the declared interface. Consider the
java.util.SortedMap<K, V> Java interface, which implements the java.util.Map<K, V> interface. Map provides a
clear method, thus a seemingly reasonable Invoker definition for SortedMap would be:
// Fails at runtime. DO NOT FOLLOW
partial class ISortedMapInvoker : Java.Lang.Object, ISortedMap {
static IntPtr class_ref = JNIEnv.FindClass ("java/util/SortedMap");
static IntPtr id_clear;
public void Clear()
{
if (id_clear == IntPtr.Zero)
id_clear = JNIEnv.GetMethodID(class_ref, "clear", "()V");
JNIEnv.CallVoidMethod(Handle, id_clear);
}
// ...
}
The above will fail because JNIEnv.GetMethodID will return null when looking up the Map.clear method
through the SortedMap class instance.
There are two solutions to this: track which interface every method comes from, and have a class_ref for each
interface, or keep everything as instance members and perform the method lookup on the most-derived class
type, not the interface type. The latter is done in Mono.Android.dll.
The Invoker definition has six sections: the constructor, the Dispose method, the ThresholdType and
ThresholdClass members, the GetObject method, interface method implementation, and the connector method
implementation.
Constructor
The constructor needs to lookup the runtime class of the instance being invoked and store the runtime class in the
instance class_ref field:
Note: The Handle property must be used within the constructor body, and not the handle parameter, as on
Android v4.0 the handle parameter may be invalid after the base constructor finishes executing.
Dispose Method
The Dispose method needs to free the global reference allocated in the constructor:
GetObject Method
A static GetObject method is required to support Extensions.JavaCast<T>():
Interface Methods
Every method of the interface needs to have an implementation, which invokes the corresponding Java method
through JNI:
Connector Methods
The connector methods and supporting infrastructure are responsible for marshaling the JNI parameters to
appropriate C# types. The Java int[] parameter will be passed as a JNI jintArray , which is an IntPtr within
C#. The IntPtr must be marshaled to a JavaArray<int> in order to support invoking the C# interface:
partial class IAdderProgressInvoker {
static Delegate cb_onAdd;
static Delegate GetOnAddHandler ()
{
if (cb_onAdd == null)
cb_onAdd = JNINativeWrapper.CreateDelegate ((Action<IntPtr, IntPtr, IntPtr, int, int>) n_OnAdd);
return cb_onAdd;
}
static void n_OnAdd (IntPtr jnienv, IntPtr lrefThis, IntPtr values, int currentIndex, int currentSum)
{
IAdderProgress __this = Java.Lang.Object.GetObject<IAdderProgress>(lrefThis,
JniHandleOwnership.DoNotTransfer);
using (var _values = new JavaArray<int>(values, JniHandleOwnership.DoNotTransfer)) {
__this.OnAdd (_values, currentIndex, currentSum);
}
}
}
If int[] would be preferred over JavaList<int> , then JNIEnv.GetArray() could be used instead:
Note, however, that JNIEnv.GetArray copies the entire array between VMs, so for large arrays this could result in
lots of added GC pressure.
Complete Invoker Definition
The complete IAdderProgressInvoker definition:
class IAdderProgressInvoker : Java.Lang.Object, IAdderProgress {
IntPtr class_ref;
#region OnAdd
IntPtr id_onAdd;
public void OnAdd (JavaArray<int> values, int currentIndex, int currentSum)
{
if (id_onAdd == IntPtr.Zero)
id_onAdd = JNIEnv.GetMethodID (class_ref, "onAdd",
"([III)V");
JNIEnv.CallVoidMethod (Handle, id_onAdd,
new JValue (JNIEnv.ToJniHandle (values)),
new JValue (currentIndex),
new JValue (currentSum));
}
static void n_OnAdd (IntPtr jnienv, IntPtr lrefThis, IntPtr values, int currentIndex, int currentSum)
{
IAdderProgress __this = Java.Lang.Object.GetObject<IAdderProgress>(lrefThis,
JniHandleOwnership.DoNotTransfer);
using (var _values = new JavaArray<int>(values, JniHandleOwnership.DoNotTransfer)) {
__this.OnAdd (_values, currentIndex, currentSum);
}
}
#pragma warning restore 0169
#endregion
}
JNI Object References
Many JNIEnv methods return JNI object references, which are similar to GCHandle s. JNI provides three different
types of object references: local references, global references, and weak global references. All three are
represented as System.IntPtr , but (as per the JNI Function Types section) not all IntPtr s returned from JNIEnv
methods are references. For example, JNIEnv.GetMethodID returns an IntPtr , but it doesn't return an object
reference, it returns a jmethodID . Consult the JNI function documentation for details.
Local references are created by most reference-creating methods. Android only allows a limited number of local
references to exist at any given time, usually 512. Local references can be deleted via JNIEnv.DeleteLocalRef.
Unlike JNI, not all reference JNIEnv methods which return object references return local references;
JNIEnv.FindClass returns a global reference. It is strongly recommended that you delete local references as
quickly as you can, possibly by constructing a Java.Lang.Object around the object and specifying
JniHandleOwnership.TransferLocalRef to the Java.Lang.Object( IntPtr handle, JniHandleOwnership transfer )
constructor.
Global references are created by JNIEnv.NewGlobalRef and JNIEnv.FindClass. They can be destroyed with
JNIEnv.DeleteGlobalRef. Emulators have a limit of 2,000 outstanding global references, while hardware devices
have a limit of around 52,000 global references.
Weak global references are only available on Android v2.2 (Froyo) and later. Weak global references can be
deleted with JNIEnv.DeleteWeakGlobalRef.
Dealing With JNI Local References
The JNIEnv.GetObjectField, JNIEnv.GetStaticObjectField, JNIEnv.CallObjectMethod,
JNIEnv.CallNonvirtualObjectMethod and JNIEnv.CallStaticObjectMethod methods return an IntPtr which
contains a JNI local reference to a Java object, or IntPtr.Zero if Java returned null . Due to the limited number
of local references that can be outstanding at once (512 entries), it is desirable to ensure that the references are
deleted in a timely fashion. There are three ways that local references can be dealt with: explicitly deleting them,
creating a Java.Lang.Object instance to hold them, and using Java.Lang.Object.GetObject<T>() to create a
managed callable wrapper around them.
Explicitly Deleting Local References
JNIEnv.DeleteLocalRef is used to delete local references. Once the local reference has been deleted, it cannot be
used anymore, so care must be taken to ensure that JNIEnv.DeleteLocalRef is the last thing done with the local
reference.
The created global reference will not be freed until the Java.Lang.Object instance is garbage collected. If you are
able to, disposing of the instance will free up the global reference, speeding up garbage collections:
Using Java.Lang.Object.GetObject<T>()
Java.Lang.Object provides a Java.Lang.Object.GetObject<T>( IntPtr handle, JniHandleOwnership transfer )
method that can be used to create a managed callable wrapper of the specified type.
The type T must fulfill the following requirements:
1. T must be a reference type.
2. T must implement the IJavaObject interface.
3. If is not an abstract class or interface, then
T T must provide a constructor with the parameter types
(IntPtr, JniHandleOwnership) .
4. If T is an abstract class or an interface, there must be an invoker available for T . An invoker is a non-
abstract type that inherits T or implements T , and has the same name as T with an Invoker suffix. For
example, if T is the interface Java.Lang.IRunnable , then the type Java.Lang.IRunnableInvoker must exist
and must contain the required (IntPtr, JniHandleOwnership) constructor.
Since the JNI method invocation methods return local refs, JniHandleOwnership.TransferLocalRef would normally
be used:
Static Fields
Static Fields are manipulated through field IDs. Field IDs are obtained via JNIEnv.GetStaticFieldID, which requires
the class that the field is defined in, the name of the field, and the JNI Type Signature of the field.
Field IDs do not need to be freed, and are valid as long as the corresponding Java type is loaded. (Android does
not currently support class unloading.)
There are two sets of methods for manipulating static fields: one for reading instance fields and one for writing
instance fields. All sets of methods require a field ID to read or write the field value.
Reading Static Field Values
The set of methods for reading static field values follows the naming pattern:
Instance Methods
Instance Methods are invoked through method IDs. Method IDs are obtained via JNIEnv.GetMethodID, which
requires the type that the method is defined in, the name of the method, and the JNI Type Signature of the
method.
Method IDs do not need to be freed, and are valid as long as the corresponding Java type is loaded. (Android
does not currently support class unloading.)
There are two sets of methods for invoking methods: one for invoking methods virtually, and one for invoking
methods non-virtually. Both sets of methods require a method ID to invoke the method, and non-virtual
invocation also requires that you specify which class implementation should be invoked.
Interface methods can only be looked up within the declaring type; methods that come from extended/inherited
interfaces cannot be looked up. See the later Binding Interfaces / Invoker Implementation section for more details.
Any method declared in the class or any base class or implemented interface can be looked up.
Virtual Method Invocation
The set of methods for invoking methods virtually follows the naming pattern:
* JNIEnv.CallNonvirtual*Method( IntPtr instance, IntPtr class, IntPtr methodID, params JValue[] args );
where * is the return type of the method. Non-virtual method invocation is usually used to invoke the base
method of a virtual method.
JNIEnv.CallNonvirtualObjectMethod – Non-virtually invoke a method which returns a non-builtin type,
such as java.lang.Object , arrays, and interfaces. The value returned is a JNI local reference.
JNIEnv.CallNonvirtualBooleanMethod – Non-virtually invoke a method which returns a bool value.
JNIEnv.CallNonvirtualByteMethod – Non-virtually invoke a method which returns a sbyte value.
JNIEnv.CallNonvirtualCharMethod – Non-virtually invoke a method which returns a char value.
JNIEnv.CallNonvirtualShortMethod – Non-virtually invoke a method which returns a short value.
JNIEnv.CallNonvirtualLongMethod – Non-virtually invoke a method which returns a long value.
JNIEnv.CallNonvirtualFloatMethod – Non-virtually invoke a method which returns a float value.
JNIEnv.CallNonvirtualDoubleMethod – Non-virtually invoke a method which returns a double value.
Static Methods
Static Methods are invoked through method IDs. Method IDs are obtained via JNIEnv.GetStaticMethodID, which
requires the type that the method is defined in, the name of the method, and the JNI Type Signature of the
method.
Method IDs do not need to be freed, and are valid as long as the corresponding Java type is loaded. (Android
does not currently support class unloading.)
Static Method Invocation
The set of methods for invoking methods virtually follows the naming pattern:
(ILjava/lang/String;[I)J
In general, it is strongly recommended to use the javap command to determine JNI signatures. For example, the
JNI Type Signature of the java.lang.Thread.State.valueOf(String) method is "
(Ljava/lang/String;)Ljava/lang/Thread$State;", while the JNI Type Signature of the java.lang.Thread.State.values
method is "()[Ljava/lang/Thread$State;". Watch out for the trailing semicolons; those are part of the JNI type
signature.
built-in
simplified
type
array
Built-in Type References
Built-in type references are a single character, used to reference built-in value types. The mapping is as follows:
"B" for sbyte .
"S" for short .
"I" for int .
"J" for long .
"F" for float .
"D" for double .
"C" for char .
"Z" for bool .
"V" for void method return types.
Simplified Type References
Simplified type references can only be used in JNIEnv.FindClass(string). There are two ways to derive a simplified
type reference:
1. From a fully-qualified Java name, replace every '.' within the package name and before the type name
with '/' , and every '.' within a type name with '$' .
2. Read the output of 'unzip -l android.jar | grep JavaName' .
Either of the two will result in the Java type java.lang.Thread.State being mapped to the simplified type reference
java/lang/Thread$State .
Type References
A type reference is a built-in type reference or a simplified type reference with an 'L' prefix and a ';' suffix.
For the Java type java.lang.String, the simplified type reference is "java/lang/String" , while the type reference is
"Ljava/lang/String;" .
Type references are used with Array type references and with JNI Signatures.
An additional way to obtain a type reference is by reading the output of
'javap -s -classpath android.jar fully.qualified.Java.Name' . Depending on the type involved, you can use a
constructor declaration or method return type to determine the JNI name. For example:
Thread.State is a Java enum type, so we can use the Signature of the valueOf method to determine that the type
reference is Ljava/lang/Thread$State;.
Array Type References
Array type references are '[' prefixed to a JNI type reference. Simplified type references cannot be used when
specifying arrays.
For example, int[] is "[I" , int[][] is "[[I" , and java.lang.Object[] is "[Ljava/lang/Object;" .
public static IntPtr NewObject(IntPtr clazz, IntPtr jmethod, params JValue[] parms);
Translating between the two calls is reasonably straightforward. In C you would have:
return instance;
}
IntPtr CreateMapActivity()
{
IntPtr Map_Class = JNIEnv.FindClass ("mono/samples/googlemaps/MyMapActivity");
IntPtr Map_defCtor = JNIEnv.GetMethodID (Map_Class, "<init>", "()V");
IntPtr instance = JNIEnv.NewObject (Map_Class, Map_defCtor);
return instance;
}
Once you have a Java Object instance held in an IntPtr, you'll probably want to do something with it. You can use
JNIEnv methods such as JNIEnv.CallVoidMethod() to do so, but if there is already an analogue C# wrapper then
you'll want to construct a wrapper over the JNI reference. You can do so through the Extensions.JavaCast ()
extension method:
Furthermore, all of the JNI functions have been modified by removing the JNIEnv* parameter present in every
JNI function.
Summary
Dealing directly with JNI is a terrible experience that should be avoided at all costs. Unfortunately, it's not always
avoidable; hopefully this guide will provide some assistance when you hit the unbound Java cases with Mono for
Android.
Related Links
SanityTests (sample)
Java Native Interface Specification
Java Native Interface Functions
Porting Java to C#
4/12/2018 • 2 minutes to read • Edit Online
A third option for using Java in a Xamarin.Android application is to port the Java source code to C#.
Overview
This approach may be of interest to organizations that:
Are switching technology stacks from Java to C#.
Must maintain a C# and a Java version of the same product.
Wish to have a .NET version of a popular Java library.
There are two ways to port Java code to C#. The first way is to port the code manually. This involves skilled
developers who understand both .NET and Java and are familiar with the proper idioms for each language. This
approach makes the most sense for small amounts of code, or for organizations that wish to completely move
away from Java to C#.
The second porting methodology is to try and automate the process by using a code converter, such as Sharpen.
Sharpen is an open source converter from Versant that was originally used to port the code for db4o from Java to
C#. db4o is an object-oriented database that Versant developed in Java, and then ported to .NET. Using a code
converter may make sense for projects that must exist in both languages and that require some parity between the
two.
An example of when an automated code conversion tool makes sense can be seen in the ngit project. Ngit is a port
of the Java project jgit. Jgit itself is a Java implementation of the Git source code management system. To generate
C# code from Java, the ngit programmers use a custom automated system to extract the Java code from jgit, apply
some patches to accommodate the conversion process, and then run Sharpen, which generates the C# code. This
allows the ngit project to benefit from the continuous, ongoing work that is done on jgit.
There is often a non-trivial amount of work involved with bootstrapping an automated code conversion tool, and
this may prove to be a barrier to use. In many cases, it may be simpler and easier to port Java to C# by hand.
Related Links
Sharpen Conversion Tool
Binding a Java Library
4/12/2018 • 7 minutes to read • Edit Online
The Android community has many Java libraries that you may want to use in your app; this guide explains how
to incorporate Java libraries into your Xamarin.Android application by creating a Bindings Library.
Overview
The third-party library ecosystem for Android is massive. Because of this, it frequently makes sense to use an
existing Android library than to create a new one. Xamarin.Android offers two ways to use these libraries:
Create a Bindings Library that automatically wraps the library with C# wrappers so you can invoke Java
code via C# calls.
Use the Java Native Interface (JNI) to invoke calls in Java library code directly. JNI is a programming
framework that enables Java code to call and be called by native applications or libraries.
This guide explains the first option: how to create a Bindings Library that wraps one or more existing Java
libraries into an assembly that you can link to in your application. For more information about using JNI, see
Working with JNI.
Xamarin.Android implements bindings by using Managed Callable Wrappers (MCW ). MCW is a JNI bridge that
is used when managed code needs to invoke Java code. Managed callable wrappers also provide support for
subclassing Java types and for overriding virtual methods on Java types. Likewise, whenever Android runtime
(ART) code wishes to invoke managed code, it does so via another JNI bridge known as Android Callable
Wrappers (ACW ). This architecture is illustrated in the following diagram:
A Bindings Library is an assembly containing Managed Callable Wrappers for Java types. For example, here is a
Java type, MyClass , that we want to wrap in a Bindings Library:
package com.xamarin.mycode;
After we generate a Bindings Library for the .jar that contains MyClass , we can instantiate it and call methods on
it from C#:
var instance = new MyClass ();
To create this Bindings Library, you use the Xamarin.Android Java Bindings Library template. The resulting
binding project creates a .NET assembly with the MCW classes, .jar file(s), and resources for Android Library
projects embedded in it. You can also create Bindings Libraries for Android Archive (.AAR ) files and Eclipse
Android Library projects. By referencing the resulting Bindings Library DLL assembly, you can reuse an existing
Java library in your Xamarin.Android project.
When you reference types in your Binding Library, you must use the namespace of your binding library. Typically,
you add a using directive at the top of your C# source files that is the .NET namespace version of the Java
package name. For example, if the Java package name for your bound .jar is the following:
com.company.package
Then you would put the following using statement at the top of your C# source files to access types in the
bound .jar file:
using Com.Company.Package;
When binding an existing Android library, it is necessary to keep the following points in mind:
Are there any external dependencies for the library? – Any Java dependencies required by the
Android library must be included in the Xamarin.Android project as a ReferenceJar or as an
EmbeddedReferenceJar. Any native assemblies must be added to the binding project as an
EmbeddedNativeLibrary.
What version of the Android API is does the Android library target? – It is not possible to
"downgrade" the Android API level; ensure that the Xamarin.Android binding project is targeting the same
API level (or higher) as the Android library.
What version of the JDK was used to compile the library? – Binding errors may occur if the Android
library was built with a different version of JDK than in use by Xamarin.Android. If possible, recompile the
Android library using the same version of the JDK that is used by your installation of Xamarin.Android.
Build Actions
When you create a Bindings Library, you set build actions on the .jar or .AAR files that you incorporate into your
Bindings Library project – each build action determines how the .jar or .AAR file will be embedded into (or
referenced by) your Bindings Library. The following list summarizes these build actions:
EmbeddedJar – Embeds the .jar into the resulting Bindings Library DLL as an embedded resource. This is
the simplest and most commonly-used build action. Use this option when you want the .jar automatically
compiled into byte code and packaged into the Bindings Library.
InputJar – Does not embed the .jar into the resulting Bindings Library .DLL. Your Bindings Library .DLL
will have a dependency on this .jar at runtime. Use this option when you do not want to include the .jar in
your Bindings Library (for example, for licensing reasons). If you use this option, you must ensure that the
input .jar is available on the device that runs your app.
– Embeds an .AAR file into the resulting Bindings Library .DLL. This is similar to
LibraryProjectZip
EmbeddedJar, except that you can access resources (as well as code) in the bound .AAR file. Use this
option when you want to embed an .AAR into your Bindings Library.
ReferenceJar – Specifies a reference .jar: a reference .jar is a .jar that one of your bound .jar or .AAR files
depends on. This reference .jar is used only to satisfy compile-time dependencies. When you use this build
action, C# bindings are not created for the reference .jar and it is not embedded in the resulting Bindings
Library .DLL. Use this option when you will make a Bindings Library for the reference .jar but have not
done so yet. This build action is useful for packaging multiple .jars (and/or .AARs) into multiple
interdependent Bindings Libraries.
EmbeddedReferenceJar – Embeds a reference .jar into the resulting Bindings Library .DLL. Use this build
action when you want to create C# bindings for both the input .jar (or .AAR ) and all of its reference .jar(s)
in your Bindings Library.
EmbeddedNativeLibrary – Embeds a native .so into the binding. This build action is used for .so files that
are required by the .jar file being bound. It may be necessary to manually load the .so library before
executing code from the Java libary. This is described below.
These build actions are explained in more detail in the following guides.
Additionally, the following build actions are used to help importing Java API documentation and convert them
into C# XML documentation:
JavaDocJar is used to point to Javadoc archive Jar for a Java library that conforms to a Maven package style
(usually FOOBAR-javadoc**.jar** ).
JavaDocIndex is used to point to index.html file within the API reference documentation HTML.
JavaSourceJar is used to complement JavaDocJar , to first generate JavaDoc from sources and then treat the
results as JavaDocIndex , for a Java library that conforms to a Maven package style (usually
FOOBAR-sources**.jar** ).
The API documentation should be the default doclet from Java8, Java7 or Java6 SDK (they are all different
format), or the DroidDoc style.
Java.Lang.JavaSystem.LoadLibrary("pocketsphinx_jni");
Binding Scenarios
The following binding scenario guides can help you bind a Java library (or libraries) for incorporation into your
app:
Binding a .JAR is a walkthrough for creating Bindings Libraries for .jar files.
Binding an .AAR is a walkthrough for creating Bindings Libraries for .AAR files. Read this walkthrough to
learn how to bind Android Studio libraries.
Binding an Eclipse Library Project is a walkthrough for creating binding libraries from Android Library
Projects. Read this walkthrough to learn how to bind Eclipse Android Library Projects.
Customizing Bindings explains how to make manual modifications to the binding to resolve build errors
and shape the resulting API so that it is more "C#-like".
Troubleshooting Bindings lists common binding error scenarios, explains possible causes, and offers
suggestions for resolving these errors.
Related Links
Working with JNI
GAPI Metadata
Using Native Libraries
Binding a .JAR
5/7/2018 • 6 minutes to read • Edit Online
This walkthrough provides step -by-step instructions for creating a Xamarin.Android Java Bindings Library from an
Android .JAR file.
Overview
The Android community offers many Java libraries that you may want to use in your app. These Java libraries are
often packaged in .JAR (Java Archive) format, but you can package a .JAR it in a Java Bindings Library so that its
functionality is available to Xamarin.Android apps. The purpose of the Java Bindings library is to make the APIs in
the .JAR file available to C# code through automatically-generated code wrappers.
Xamarin tooling can generate a Bindings Library from one or more input .JAR files. The Bindings Library (.DLL
assembly) contains the following:
The contents of the original .JAR file(s).
Managed Callable Wrappers (MCW ), which are C# types that wrap corresponding Java types within the
.JAR file(s).
The generated MCW code uses JNI (Java Native Interface) to forward your API calls to the underlying .JAR file.
You can create bindings libraries for any .JAR file that was originally targeted to be used with Android (note that
Xamarin tooling does not currently support the binding of non-Android Java libraries). You can also elect to build
the Bindings Library without including the contents of the .JAR file so that the DLL has a dependency on the .JAR
at runtime.
In this guide, we'll step through the basics of creating a Bindings Library for a single .JAR file. We'll illustrate with
an example where everything goes right – that is, where no customization or debugging of bindings is required.
Creating Bindings Using Metadata offers an example of a more advanced scenario where the binding process is
not entirely automatic and some amount of manual intervention is required. For an overview of Java library
binding in general (with a basic code example), see Binding a Java Library.
Walkthrough
In the following walkthrough, we'll create a Bindings Library for Picasso, a popular Android .JAR that provides
image loading and caching functionality. We will use the following steps to bind picasso-2.x.x.jar to create a new
.NET assembly that we can use in a Xamarin.Android project:
1. Create a new Java Bindings Library project.
2. Add the .JAR file to the project.
3. Set the appropriate build action for the .JAR file.
4. Choose a target framework that the .JAR supports.
5. Build the Bindings Library.
Once we've created the Bindings Library, we'll develop a small Android app that demonstrates our ability to call
APIs in the Bindings Library. In this example, we want to access methods of picasso-2.x.x.jar:
package com.squareup.picasso
```csharp
After we generate a Bindings Library for **picasso-2.x.x.jar**,
we can call these methods from C#. For example:
```csharp
using Com.Squareup.Picasso;
...
Picasso.With (this)
.Load ("http://mydomain.myimage.jpg")
.Into (imageView);
The template includes a Jars folder where you add your .JAR (s) to the Bindings Library project. Right-click the Jars
folder and select Add > Existing Item:
Navigate to the picasso-2.x.x.jar file downloaded earlier, select it and click Add:
Verify that the picasso-2.x.x.jar file was successfully added to the project:
When you create a Java Bindings library project, you must specify whether the .JAR is to be embedded in the
Bindings Library or packaged separately. To do that, you specify one of the following build actions:
EmbeddedJar – the .JAR will be embedded in the Bindings Library.
InputJar – the .JAR will be kept separate from the Bindings Library.
Typically, you use the EmbeddedJar build action so that the .JAR is automatically packaged into the bindings
library. This is the simplest option – Java bytecode in the .JAR is converted into Dex bytecode and is embedded
(along with the Managed Callable Wrappers) into your APK. If you want to keep the .JAR separate from the
bindings library, you can use the InputJar option; however, you must ensure that the .JAR file is available on the
device that runs your app.
Set the build action to EmbeddedJar:
Next, open the project Properties to configure the Target Framework. If the .JAR uses any Android APIs, set the
Target Framework to the API level that the .JAR expects. Typically, the developer of the .JAR file will indicate which
API level (or levels) that the .JAR is compatible with. (For more information about the Target Framework setting
and Android API levels in general, see Understanding Android API Levels.)
Set the target API level for your Bindings Library (in this example, we are using API level 19):
Finally, build the Bindings Library. Although some warning messages may be displayed, the Bindings Library
project should build successfully and produce an output .DLL at the following location:
JarBinding/bin/Debug/JarBinding.dll
Using the Bindings Library
To consume this .DLL in your Xamarin.Android app, do the following:
1. Add a reference to the Bindings Library.
2. Make calls into the .JAR through the Managed Callable Wrappers.
In the following steps, we'll create a minimal app that uses the Bindings Library to download and display an image
in an ImageView ; the "heavy lifting" is done by the code that resides in the .JAR file.
First, create a new Xamarin.Android app that consumes the Bindings Library. Right-click the Solution and select
Add New Project; name the new project BindingTest. We're creating this app in the same Solution as the
Bindings Library in order to simplify this walkthrough; however, the app that consumes the Bindings Library could,
instead, reside in a different Solution:
Right-click the References node of the BindingTest project and select Add Reference...:
Add the following using statement to MainActivity.cs – this makes it possible to easily access the methods of
the Java-based Picasso class that resides in the Bindings Library:
using Com.Squareup.Picasso;
Modify the OnCreate method so that it uses the Picasso class to load an image from a URL and display it in the
ImageView :
// Use the Picasso jar library to load and display this image:
Picasso.With (this)
.Load ("http://i.imgur.com/DvpvklR.jpg")
.Into (imageView);
}
}
Compile and run the BindingTest project. The app will startup, and after a short delay (depending on network
conditions), it should download and display an image similar to the following screenshot:
Congratulations! You've successfully bound a Java library .JAR and used it in your Xamarin.Android app.
Summary
In this walkthrough, we created a Bindings Library for a third-party .JAR file, added the Bindings Library to a
minimal test app, and then ran the app to verify that our C# code can call Java code residing in the .JAR file.
Related Links
Building a Java Bindings Library (video)
Binding a Java Library
Binding an .AAR
5/7/2018 • 7 minutes to read • Edit Online
This walkthrough provides step -by-step instructions for creating a Xamarin.Android Java Bindings Library from an
Android .AAR file.
Overview
The Android Archive (.AAR ) file is the file format for Android libraries. An .AAR file is a .ZIP archive that contains
the following:
Compiled Java code
Resource IDs
Resources
Meta-data (for example, Activity declarations, permissions)
In this guide, we'll step through the basics of creating a Bindings Library for a single .AAR file. For an overview of
Java library binding in general (with a basic code example), see Binding a Java Library.
IMPORTANT
A binding project can only include one .AAR file. If the .AAR dependencies on other .AAR, then those dependencies should be
contained in their own binding project and then referenced. See Bug 44573.
Walkthrough
We'll create a Bindings Library for an example Android archive file that was created in Android Studio,
textanalyzer.aar. This .AAR contains a TextCounter class with static methods that count the number of vowels and
consonants in a string. In addition, textanalyzer.aar contains an image resource to help display the counting
results.
We'll use the following steps to create a Bindings Library from the .AAR file:
1. Create a new Java Bindings Library project.
2. Add a single .AAR file to the project. A binding project may only contain a single .AAR.
3. Set the appropriate build action for the .AAR file.
4. Choose a target framework that the .AAR supports.
5. Build the Bindings Library.
Once we've created the Bindings Library, we'll develop a small Android app that prompts the user for a text string,
calls .AAR methods to analyze the text, retrieves the image from the .AAR, and displays the results along with the
image.
The sample app will access the TextCounter class of textanalyzer.aar:
package com.xamarin.textcounter;
In addition, this sample app will retrieve and display an image resource that is packaged in textanalyzer.aar:
2. The template includes a Jars folder where you add your .AAR (s) to the Bindings Library project. Right-click
the Jars folder and select Add > Existing Item:
3. Navigate to the textanalyzer.aar file downloaded earlier, select it, and click Add:
4. Verify that the textanalyzer.aar file was successfully added to the project:
5. Set the Build Action for textanalyzer.aar to LibraryProjectZip . In Visual Studio for Mac, right-click
textanalyzer.aar to set the Build Action. In Visual Studio, the Build Action can be set in the Properties
pane):
6. Open the project Properties to configure the Target Framework. If the .AAR uses any Android APIs, set the
Target Framework to the API level that the .AAR expects. (For more information about the Target
Framework setting and Android API levels in general, see Understanding Android API Levels.)
Set the target API level for your Bindings Library. In this example, we are free to use the latest platform API
level (API level 23) because our textanalyzer does not have a dependency on Android APIs:
7. Build the Bindings Library. The Bindings Library project should build successfully and produce an output
.DLL at the following location: AarBinding/bin/Debug/AarBinding.dll
Using the Bindings Library
To consume this .DLL in your Xamarin.Android app, you must first add a reference to the Bindings Library. Use the
following steps:
1. We're creating this app in the same Solution as the Bindings Library to simplify this walkthrough. (The app
that consumes the Bindings Library could also reside in a different Solution.) Create a new Xamarin.Android
app: right-click the Solution and select Add New Project. Name the new project BindingTest:
2. Right-click the References node of the BindingTest project and select Add Reference...:
3. Select the AarBinding project created earlier and click OK:
4. Open the References node of the BindingTest project to verify that the AarBinding reference is present:
If you would like to view the contents of the Binding Library project, you can double-click the reference to open it
in the Object Browser. You can see the mapped contents of the Com.Xamarin.Textcounter namespace (mapped
from the Java com.xamarin.textanalyzezr package) and you can view the members of the TextCounter class:
The above screenshot highlights the two TextAnalyzer methods that the example app will call: NumConsonants
(which wraps the underlying Java numConsonants method), and NumVowels (which wraps the underlying Java
numVowels method).
using Com.Xamarin.Textcounter;
...
int numVowels = TextCounter.NumVowels (myText);
int numConsonants = TextCounter.NumConsonants (myText);
In the above example, we're calling static methods in the TextCounter class. However, you can also instantiate
classes and call instance methods. For example, if your .AAR wraps a class called Employee that has the instance
method buildFullName , you can instantiate MyClass and use it as seen here:
The following steps add code to the app so that it prompts the user for text, uses TextCounter to analyze the text,
and then displays the results.
Replace the BindingTest layout (Main.axml) with the following XML. This layout has an EditText for text input
and two buttons for initiating vowel and consonant counts:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation ="vertical"
android:layout_width ="fill_parent"
android:layout_height ="fill_parent" >
<TextView
android:text ="Text to analyze:"
android:textSize ="24dp"
android:layout_marginTop ="30dp"
android:layout_gravity ="center"
android:layout_width ="wrap_content"
android:layout_height ="wrap_content" />
<EditText
android:id ="@+id/input"
android:text ="I can use my .AAR file from C#!"
android:layout_marginTop ="10dp"
android:layout_gravity ="center"
android:layout_width ="300dp"
android:layout_height ="wrap_content"/>
<Button
android:id ="@+id/vowels"
android:layout_marginTop ="30dp"
android:layout_width ="240dp"
android:layout_height ="wrap_content"
android:layout_gravity ="center"
android:text ="Count Vowels" />
<Button
android:id ="@+id/consonants"
android:layout_width ="240dp"
android:layout_height ="wrap_content"
android:layout_gravity ="center"
android:text ="Count Consonants" />
</LinearLayout>
Replace the contents of MainActivity.cs with the following code. As seen in this example, the button event
handlers call wrapped TextCounter methods that reside in the .AAR and use toasts to display the results. Notice
the using statement for the namespace of the bound library (in this case, Com.Xamarin.Textcounter ):
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Android.Views.InputMethods;
using Com.Xamarin.Textcounter;
namespace BindingTest
{
[Activity(Label = "BindingTest", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
InputMethodManager imm;
SetContentView(Resource.Layout.Main);
imm = (InputMethodManager)GetSystemService(Context.InputMethodService);
}
}
}
Compile and run the BindingTest project. The app will start and present the screenshot on the left (the EditText
is initialized with some text, but you can tap it to change it). When you tap COUNT VOWELS, a toast displays the
number of vowels as shown on the right:
Try tapping the COUNT CONSONANTS button. Also, you can modify the line of text and tap these buttons again
to test for different vowel and consonant counts.
Accessing .AAR Resources
The Xamarin tooling merges the R data from the .AAR into your app's Resource class. As a result, you can access
.AAR resources from your layout (and from code-behind) in the same way as you would access resources that are
in the Resources path of your project.
To access an image resource, you use the Resource.Drawable name for the image packed inside the .AAR. For
example, you can reference image.png in the .AAR file by using @drawable/image :
You can also access resource layouts that reside in the .AAR. To do this, you use the Resource.Layout name for
the layout packaged inside the .AAR. For example:
The textanalyzer.aar example contains an image file that resides at res/drawable/monkey.png. Let's access this
image resource and use it in our example app:
Edit the BindingTest layout (Main.axml) and add an ImageView to the end of the LinearLayout container. This
ImageView displays the image found at **@drawable/monkey**; this image will be loaded from the resource
section of textanalyzer.aar:
...
<ImageView
android:src ="@drawable/monkey"
android:layout_marginTop ="40dp"
android:layout_width ="200dp"
android:layout_height ="200dp"
android:layout_gravity ="center" />
</LinearLayout>
Compile and run the BindingTest project. The app will start and present the screenshot on the left – when you tap
COUNT CONSONANTS, the results are displayed as shown on the right:
Summary
In this walkthrough, we created a Bindings Library for an .AAR file, added the Bindings Library to a minimal test
app, and ran the app to verify that our C# code can call Java code residing in the .AAR file. In addition, we extended
the app to access and display an image resource that resides in the .AAR file.
Related Links
Building a Java Bindings Library (video)
Binding a .JAR
Binding a Java Library
AarBinding (sample)
Bug 44573 - One project cannot bind multiple .aar files
Binding an Eclipse Library Project
4/12/2018 • 2 minutes to read • Edit Online
This walkthrough explains how to use Xamarin.Android project templates to bind an Eclipse Android library
project.
Overview
Although .AAR files are increasingly becoming the norm for Android library distribution, in some cases it is
necessary to create a binding for an Android library project. Android library projects are special Android projects
that contain shareable code and resources that can be referenced by Android application projects. Typically, you
bind to an Android library project when the library is created in the Eclipse IDE. This walkthrough provides
examples of how to create an Android library project .ZIP from the directory structure of an Eclipse project.
Android library projects are different from regular Android projects in that they are not compiled into an APK and
are not, on their own, deployable to a device. Instead, an Android library project is meant to be referenced by an
Android application project. When an Android application project is built, the Android library project is compiled
first. The Android application project will then be absorbed into the compiled Android library project and include
the code and resources into the APK for distribution. Because of this difference, creating a binding for an Android
library project is slightly different than creating a binding for a Java .JAR or .AAR file.
Walkthrough
To use an Android library project in a Xamarin.Android Java Binding project it is first necessary to build the
Android library project in Eclipse. The following screenshot shows an example of one Android library project after
compilation:
Notice that the source code from the Android library project has been compiled to a temporary .JAR file named
android-mapviewballoons.jar, and that the resources have been copied to the bin/res/crunch folder.
Once the Android library project has been compiled in Eclipse, it can then be bound using a Xamarin.Android Java
Binding project. First a .ZIP file must be created which contains the bin and res folders of the Android library
project. It is important that you remove the intervening crunch subdirectory so that the resources reside in
bin/res. The following screenshot shows the contents of one such .ZIP file:
This .ZIP file is then added to Xamarin.Android Java Binding project, as shown in the following screenshot:
Notice that the Build Action of the .ZIP file has been automatically set to LibraryProjectZip.
If there are any .JAR files that are required by the Android library project, they should be added to the Jars folder
of the Java Binding Library project and the Build Action set to ReferenceJar. An example of this can be seen in
the screenshot below:
Once these steps are complete, the Xamarin.Android Java Binding project can be used as described earlier on in
this document.
NOTE
Compiling the Android library projects in other IDEs is not supported at this time. Other IDEs may not create the same
directory structure or files in the bin folder as Eclipse.
Summary
In this article, we walked through the process of binding an Android library project. We built the Android library
project in Eclipse, then we created a zip file from the bin and res folders of the Android library project. Next, we
used this zip to create a Xamarin.Android Java Binding project.
Customizing Bindings
4/12/2018 • 2 minutes to read • Edit Online
You can customize an Xamarin.Android binding by editing the metadata that controls the binding process. These
manual modifications are often necessary for resolving build errors and for shaping the resulting API so that it is
more consistent with C#/.NET. These guides explain the structure of this metadata, how to modify the metadata,
and how to use JavaDoc to recover the names of method parameters.
Overview
Xamarin.Android automates much of the binding process; however, in some cases manual modification is required
to address the following issues:
Resolving build errors caused by missing types, obfuscated types, duplicate names, class visibility issues,
and other situations that cannot be resolved by the Xamarin.Android tooling.
Changing the mapping that Xamarin.Android uses to bind the Android API to different types in C# (for
example, many developers prefer to map Java int constants to C# enum constants).
Removing unused types that do not need to be bound.
Adding types that have no counterpart in the underlying Java API.
You can make some or all of these changes by modifying the metadata that controls the binding process.
Guides
The following guides describe the metadata that controls the binding process and explain how to modify this
metadata to address these issues:
Java Bindings Metadata provides an overview of the metadata that goes into a Java binding. It describes the
various manual steps that are sometimes required to complete a Java binding library, and it explains how to
shape an API exposed by a binding to more closely follow .NET design guidelines.
Naming Parameters with Javadoc explains how to recover parameter names in a Java Binding Project by
using Javadoc produced from the bound Java project.
Java Bindings Metadata
4/12/2018 • 10 minutes to read • Edit Online
C# code in Xamarin.Android calls Java libraries through bindings, which are a mechanism that abstracts the low -
level details that are specified in Java Native Interface (JNI ). Xamarin.Android provides a tool that generates these
bindings. This tooling lets the developer control how a binding is created by using metadata, which allows
procedures such as modifying namespaces and renaming members. This document discusses how metadata
works, summarizes the attributes that metadata supports, and explains how to resolve binding problems by
modifying this metadata.
Overview
A Xamarin.Android Java Binding Library tries to automate much of the work necessary for binding an existing
Android library with the help of a tool sometimes known as the Bindings Generator. When binding a Java library,
Xamarin.Android will inspect the Java classes and generate a list of all the packages, types, and members which to
be bound. This list of APIs is stored in an XML file that can be found at {project directory}\obj\Release\api.xml
for a RELEASE build and at {project directory}\obj\Debug\api.xml for a DEBUG build.
The Bindings Generator will use the api.xml file as a guideline for generating the necessary C# wrapper classes.
The contents of this XML file are a variation of Google's Android Open Source Project format. The following
snippet is an example of the contents of api.xml:
<api>
<package name="android">
<class abstract="false" deprecated="not deprecated" extends="java.lang.Object"
extends-generic-aware="java.lang.Object"
final="true"
name="Manifest"
static="false"
visibility="public">
<constructor deprecated="not deprecated" final="false"
name="Manifest" static="false" type="android.Manifest"
visibility="public">
</constructor>
</class>
...
</api>
In this example, api.xml declares a class in the android package named Manifest that extends the
java.lang.Object .
In many cases, human assistance is required to make the Java API feel more ".NET like" or to correct issues that
prevent the binding assembly from compiling. For example, it may be necessary to change Java package names to
.NET namespaces, rename a class, or change the return type of a method.
These changes are not achieved by modifying api.xml directly. Instead, changes are recorded in special XML files
that are provided by the Java Binding Library template. When compiling the Xamarin.Android binding assembly,
the Bindings Generator will be influenced by these mapping files when creating the binding assembly
These XML mapping files may be found in the Transforms folder of the project:
MetaData.xml – Allows changes to be made to the final API, such as changing the namespace of the
generated binding.
EnumFields.xml – Contains the mapping between Java int constants and C# enums .
EnumMethods.xml – Allows changing method parameters and return types from Java int constants to
C# enums .
The MetaData.xml file is the most import of these files as it allows general-purpose changes to the binding such
as:
Renaming namespaces, classes, methods, or fields so they follow .NET conventions.
Removing namespaces, classes, methods, or fields that aren't needed.
Moving classes to different namespaces.
Adding additional support classes to make the design of the binding follow .NET framework patterns.
Lets move on to discuss Metadata.xml in more detail.
<!-- Don't need these packages for the Xamarin binding/public API -->
<remove-node path="/api/package[@name='com.evernote.android.job.v14']" />
<remove-node path="/api/package[@name='com.evernote.android.job.v21']" />
<!-- Change a parameter name from the generic p0 to a more meaningful one. -->
<attr
path="/api/package[@name='com.evernote.android.job']/class[@name='JobManager']/method[@name='forceApi']/parame
ter[@name='p0']"
name="name">api</attr>
</metadata>
The following lists some of the more commonly used XPath elements for the Java API's:
interface – Used to locate a Java interface. e.g. /interface[@name='AuthListener'] .
class – Used to locate a class . e.g. /class[@name='MapView'] .
method – Used to locate a method on a Java class or interface. e.g.
/class[@name='MapView']/method[@name='setTitleSource'] .
Adding Types
The add-node element will tell the Xamarin.Android binding project to add a new wrapper class to api.xml. For
example, the following snippet will direct the Binding Generator to create a class with a constructor and a single
field:
<add-node path="/api/package[@name='org.alljoyn.bus']">
<class abstract="false" deprecated="not deprecated" final="false" name="AuthListener.AuthRequest"
static="true" visibility="public" extends="java.lang.Object">
<constructor deprecated="not deprecated" final="false" name="AuthListener.AuthRequest" static="false"
type="org.alljoyn.bus.AuthListener.AuthRequest" visibility="public" />
<field name="p0" type="org.alljoyn.bus.AuthListener.Credentials" />
</class>
</add-node>
Removing Types
It is possible to instruct the Xamarin.Android Bindings Generator to ignore a Java type and not bind it. This is done
by adding a remove-node XML element to the metadata.xml file:
Renaming Members
Renaming members cannot be done by directly editing the api.xml file because Xamarin.Android requires the
original Java Native Interface (JNI) names. Therefore, the //class/@name attribute cannot be altered; if it is, the
binding will not work.
Consider the case where we want to rename a type, android.Manifest . To accomplish this, we might try to directly
edit api.xml and rename the class like so:
<attr path="/api/package[@name='android']/class[@name='Manifest']"
name="name">NewName</attr>
This will result in the Bindings Generator creating the following C# code for the wrapper class:
[Register ("android/NewName")]
public class NewName : Java.Lang.Object { ... }
Notice that the wrapper class has been renamed to NewName , while the original Java type is still Manifest . It is no
longer possible for the Xamarin.Android binding class to access any methods on android.Manifest ; the wrapper
class is bound to a non-existent Java type.
To properly change the managed name of a wrapped type (or method), it is necessary to set the managedName
attribute as shown in this example:
<attr path="/api/package[@name='android']/class[@name='Manifest']"
name="managedName">NewName</attr>
com.someapp.android.mpa.guidance.NavigationManager.on2DSignNextManuever(NextManueverListener listener);
Xamarin.Android will drop the prefix on from the setter method and instead use 2DSignNextManuever as the basis
for the name of the EventArgs subclass. The subclass will be named something similar to:
NavigationManager.2DSignNextManueverEventArgs
This is not a legal C# class name. To correct this problem, the binding author must use the argsType attribute and
provide a valid C# name for the EventArgs subclass:
<attr path="/api/package[@name='com.someapp.android.mpa.guidance']/
interface[@name='NavigationManager.Listener']/
method[@name='on2DSignNextManeuver']"
name="argsType">NavigationManager.TwoDSignNextManueverEventArgs</attr>
Supported Attributes
The following sections describe some of the attributes for transforming Java APIs.
argsType
This attribute is placed on setter methods to name the EventArg subclass that will be generated to support Java
listeners. This is described in more detail below in the section Renaming EventArg Wrapper Classes later on in this
guide.
eventName
Specifies a name for an event. If empty, it inhibits event generation. This is described in more detail in the section
title Renaming EventArg Wrapper Classes.
managedName
This is used to change the name of a package, class, method, or parameter. For example to change the name of the
Java class MyClass to NewClassName :
<attr path="/api/package[@name='com.my.application']/class[@name='MyClass']"
name="managedName">NewClassName</attr>
The next example illustrates an XPath expression for renaming the method java.lang.object.toString to
Java.Lang.Object.NewManagedName :
<attr path="/api/package[@name='java.lang']/class[@name='Object']/method[@name='toString']"
name="managedName">NewMethodName</attr>
managedType
managedType is used to change the return type of a method. In some situations the Bindings Generator will
incorrectly infer the return type of a Java method, which will result in a compile time error. One possible solution
in this situation is to change the return type of the method.
For example, the Bindings Generator believes that the Java method de.neom.neoreadersdk.resolution.compareTo()
should return an int , which results in the error message Error CS0535: 'DE.Neom.Neoreadersdk.Resolution'
does not implement interface member 'Java.Lang.IComparable.CompareTo(Java.Lang.Object)'. The
following snippet demonstrates how to change the return type of the generated C# method from an int to a
Java.Lang.Object :
<attr path="/api/package[@name='de.neom.neoreadersdk']/
class[@name='Resolution']/
method[@name='compareTo' and count(parameter)=1 and
parameter[1][@type='de.neom.neoreadersdk.Resolution']]/
parameter[1]"name="managedType">Java.Lang.Object</attr>
managedReturn
Changes the return type of a method. This does not change the return attribute (as changes to return attributes
can result in incompatible changes to the JNI signature). In the following example, the return type of the append
method is changed from SpannableStringBuilder to IAppendable (recall that C# does not support covariant return
types):
<attr path="/api/package[@name='android.text']/
class[@name='SpannableStringBuilder']/
method[@name='append']"
name="managedReturn">Java.Lang.IAppendable</attr>
obfuscated
Tools that obfuscate Java libraries may interfere with the Xamarin.Android Binding Generator and its ability to
generate C# wrapper classes. Characteristics of obfuscated classes include: * The class name includes a $, i.e.
a$.class * The class name is entirely compromised of lower case characters, i.e. a.class
This snippet is an example of how to generate an "un-obfuscated" C# type:
<attr path="/api/package[@name='{package_name}']/class[@name='{name}']"
name="obfuscated">false</attr>
propertyName
This attribute can be used to change the name of a managed property.
A specialized case of using propertyName involves the situation where a Java class has only a getter method for a
field. In this situation the Binding Generator would want to create a write-only property, something that is
discouraged in .NET. The following snippet shows how to "remove" the .NET properties by setting the
propertyName to an empty string:
<attr
path="/api/package[@name='org.java_websocket.handshake']/class[@name='HandshakeImpl1Client']/method[@name='set
ResourceDescriptor'
and count(parameter)=1
and parameter[1][@type='java.lang.String']]"
name="propertyName"></attr>
<attr
path="/api/package[@name='org.java_websocket.handshake']/class[@name='HandshakeImpl1Client']/method[@name='get
ResourceDescriptor'
and count(parameter)=0]"
name="propertyName"></attr>
Note that the setter and getter methods will still be created by the Bindings Generator.
sender
Specifies which parameter of a method should be the sender parameter when the method is mapped to an event.
The value can be true or false . For example:
<attr path="/api/package[@name='android.app']/
interface[@name='TimePickerDialog.OnTimeSetListener']/
method[@name='onTimeSet']/
parameter[@name='view']"
name="sender">true</ attr>
visibility
This attribute is used to change the visibility of a class, method, or property. For example, it may be necessary to
promote a protected Java method so that it's corresponding C# wrapper is public :
Here we have taken the Java class SKRealReachSettings and defined a C# enum called SKMeasurementUnit in the
namespace Skobbler.Ngx.Map.RealReach . The field entries defines the name of the Java constant (example
UNIT_SECOND ), the name of the enum entry (example Second ), and the integer value represented by both entities
(example 0 ).
Defining Getter/Setter Methods using EnumMethods.xml
The EnumMethods.xml file allows changing method parameters and return types from Java int constants to
C# enums . In other words, it maps the reading and writing of C# enums (defined in the EnumFields.xml file) to
Java int constant get and set methods.
Given the SKRealReachSettings enum defined above, the following EnumMethods.xml file would define the
getter/setter for this enum:
<mapping jni-class="com/skobbler/ngx/map/realreach/SKRealReachSettings">
<method jni-name="getMeasurementUnit" parameter="return" clr-enum-
type="Skobbler.Ngx.Map.RealReach.SKMeasurementUnit" />
<method jni-name="setMeasurementUnit" parameter="measurementUnit" clr-enum-
type="Skobbler.Ngx.Map.RealReach.SKMeasurementUnit" />
</mapping>
The first method line maps the return value of the Java getMeasurementUnit method to the SKMeasurementUnit
enum. The second method line maps the first parameter of the setMeasurementUnit to the same enum.
With all of these changes in place, you can use the follow code in Xamarin.Android to set the MeasurementUnit :
realReachSettings.MeasurementUnit = SKMeasurementUnit.Second;
Summary
This article discussed how Xamarin.Android uses metadata to transform an API definition from the Google AOSP
format. After covering the changes that are possible using Metadata.xml, it examined the limitations encountered
when renaming members and it presented the list of supported XML attributes, describing when each attribute
should be used.
Related Links
Working with JNI
Binding a Java Library
GAPI Metadata
Naming Parameters With Javadoc
4/12/2018 • 2 minutes to read • Edit Online
This article explains how to recover parameter names in an Java Binding Project by using Javadoc generated from
the Java project.
Overview
When binding an existing Java library, some metadata about the bound API is lost. In particular the names of
parameters to methods. Parameter names will appear as p0 , p1 , etc. This is because the Java .class files do not
preserve the parameter names that were used in the Java source code.
A Xamarin.Android Java binding project can provide the parameter names if it has access to the Javadoc HTML
from the original library.
NOTE
There is a great deal of variance in the JavaDoc output. The .JAR binding toolchain does not support every single possible
permutation and consequently some parameter may not be properly named.
Summary
This article covered how use Javadoc in a Java Binding Project to provide meaning parameter names for bound
APIs.
Troubleshooting Bindings
4/12/2018 • 9 minutes to read • Edit Online
This article summarizes serveral common errors that may occur when generating bindings, along with possible
causes and suggested ways to resolve them.
Overview
Binding an Android library (an .aar or a .jar) file is seldom a straightforward affair; it usually requires additional
effort to mitigate issues that result from the differences between Java and .NET. These issues will prevent
Xamarin.Android from binding the Android library and present themselves as error messages in the build log. This
guide will provide some tips for troubleshooting the issues, list some of the more common problems/scenarios,
and provide possible solutions to successfully binding the Android library.
When binding an existing Android library, it is necessary to keep in mind the following points:
The external dependencies for the library – Any Java dependencies required by the Android library
must be included in the Xamarin.Android project as a ReferenceJar or as an EmbeddedReferenceJar.
The Android API level that the Android library is targetting – It is not possible to "downgrade" the
Android API level; ensure that the Xamarin.Android binding project is targeting the same API level (or
higher) as the Android library.
The version of the Android JDK that was used to package the Android library – Binding errors may
occur if the Android library was built with a different version of JDK than the one in use by
Xamarin.Android. If possible, recompile the Android library using the same version of the JDK that is used
by your installation of Xamarin.Android.
The first step to troubleshooting issues with binding a Xamarin.Android library is to enable diagnostic MSBuild
output. After enabling the diagnostic output, rebuild the Xamarin.Android binding project and examine the build
log to locate clues about what the cause of problem is.
It can also prove helpful to decompile the Android library and examine the types and methods that
Xamarin.Android is trying to bind. This is covered in more detail later on in this guide.
NOTE
Decompiling a Java library may be prohibited or subject to legal restrictions based on local laws or the license under which
the Java library was published. If necessary, enlist the services of a legal professional before attempting to decompile a Java
library and inspect the source code.
Inspect API.XML
As a part of building a binding project, Xamarin.Android will generate an XML file name obj/Debug/api.xml:
This file provides a list of all the Java APIs that Xamarin.Android is trying bind. The contents of this file can help
identify any missing types or methods, duplicate binding. Although inspection of this file is tedious and time
consuming, it can provide for clues on what might be causing any binding problems. For example, api.xml might
reveal that a property is returning an inappropriate type, or that there are two types that share the same managed
name.
Known Issues
This section will list some of the common error messages or symptoms that my occur when trying to bind an
Android library.
Problem: Java Version Mismatch
Sometimes types will not be generated or unexpected crashes may occur because you are using either a newer or
older version of Java compared to what the library was compiled with. Recompile the Android library with the
same version of the JDK that your Xamarin.Android project is using.
Problem: At least one Java library is required
You receive the error "at least one Java library is required," even though a .JAR has been added.
Possible Causes:
Make sure the build action is set to EmbeddedJar . Since there are multiple build actions for .JAR files (such as
InputJar , EmbeddedJar , ReferenceJar and EmbeddedReferenceJar ), the binding generator cannot automatically
guess which one to use by default. For more information about build actions, see Build Actions.
Problem: Binding tools cannot load the .JAR library
The binding library generator fails to load the .JAR library.
Possible Causes
Some .JAR libraries that use code obfuscation (via tools such as Proguard) cannot be loaded by the Java tools.
Since our tool makes use of Java reflection and the ASM byte code engineering library, those dependent tools may
reject the obfuscated libraries while Android runtime tools may pass. The workaround for this is to hand-bind
these libraries instead of using the binding generator.
Problem: Missing C# types in generated output.
The binding .dll builds but misses some Java types, or the generated C# source does not build due to an error
stating there are missing types.
Possible Causes:
This error may occur due to several reasons as listed below:
The library being bound may reference a second Java library. If the public API for the bound library uses
types from the second library, you must reference a managed binding for the second library as well.
It is possible that a library was injected due to Java reflection, similar to the reason for the library load error
above, causing the unexpected loading of metadata. Xamarin.Android's tooling cannot currently resolve this
situation. In such a case, the library must be manually bound.
There was a bug in .NET 4.0 runtime that failed to load assemblies when it should have. This issue has been
fixed in the .NET 4.5 runtime.
Java allows deriving a public class from non-public class, but this is unsupported in .NET. Since the binding
generator does not generate bindings for non-public classes, derived classes such as these cannot be
generated correctly. To fix this, either remove the metadata entry for those derived classes using the
remove-node in Metadata.xml, or fix the metadata that is making the non-public class public. Although the
latter solution will create the binding so that the C# source will build, the non-public class should not be
used.
For example:
<attr path="/api/package[@name='com.some.package']/class[@name='SomeClass']"
name="visibility">public</attr>
Tools that obfuscate Java libraries may interfere with the Xamarin.Android Binding Generator and its ability
to generate C# wrapper classes. The following snippet shows how to update Metadata.xml to unobfuscate
a class name:
<attr path="/api/package[@name='{package_name}']/class[@name='{name}']"
name="obfuscated">false</attr>
Problem: Generated C# source does not build due to parameter type mismatch
The generated C# source does not build. Overridden method's parameter types do not match.
Possible Causes:
Xamarin.Android includes a variety of Java fields that are mapped to enums in the C# bindings. These can cause
type incompatibilities in the generated bindings. To resolve this, the method signatures created from the binding
generator need to be modified to use the enums. For more imformation, please see Correcting Enums.
Problem: NoClassDefFoundError in packaging
java.lang.NoClassDefFoundError is thrown in the packaging step.
Possible Causes:
The most likely reason for this error is that a mandatory Java library needs to be added to the application project
(.csproj). .JAR files are not automatically resolved. A Java library binding is not always generated against a user
assembly that does not exist in the target device or emulator (such as Google Maps maps.jar). This is not the case
for Android Library project support, as the library .JAR is embedded in the library dll. For example: Bug 4288
Problem: Duplicate custom EventArgs types
Build fails due to duplicate custom EventArgs types. An error like this occurs:
Possible Causes:
This is because there is some conflict between event types that come from more than one interface "listener" type
that shares methods having identical names. For example, if there are two Java interfaces as seen in the example
below, the generator creates DismissScreenEventArgs for both MediationBannerListener and
MediationInterstitialListener , resulting in the error.
// Java:
public interface MediationBannerListener {
void onDismissScreen(MediationBannerAdapter p0);
}
public interface MediationInterstitialListener {
void onDismissScreen(MediationInterstitialAdapter p0);
}
This is by design so that lengthy names on event argument types are avoided. To avoid these conflicts, some
metadata transformation is required. Edit Transforms\Metadata.xml and add an argsType attribute on either of
the interfaces (or on the interface method):
<attr path="/api/package[@name='com.google.ads.mediation']/
interface[@name='MediationBannerListener']/method[@name='onDismissScreen']"
name="argsType">BannerDismissScreenEventArgs</attr>
<attr path="/api/package[@name='com.google.ads.mediation']/
interface[@name='MediationInterstitialListener']/method[@name='onDismissScreen']"
name="argsType">IntersitionalDismissScreenEventArgs</attr>
<attr path="/api/package[@name='android.content']/
interface[@name='DialogInterface.OnClickListener']"
name="argsType">DialogClickEventArgs</attr>
obj\Debug\generated\src\Oauth.Signpost.Basic.HttpURLConnectionRequestAdapter.cs(8,23):
error CS0738: 'Oauth.Signpost.Basic.HttpURLConnectionRequestAdapter' does not
implement interface member 'Oauth.Signpost.Http.IHttpRequest.Unwrap()'.
'Oauth.Signpost.Basic.HttpURLConnectionRequestAdapter.Unwrap()' cannot implement
'Oauth.Signpost.Http.IHttpRequest.Unwrap()' because it does not have the matching
return type of 'Java.Lang.Object'
Possible Causes:
This is a problem that occurs with binding Java methods with covariant return types. In this example, the method
Oauth.Signpost.Http.IHttpRequest.UnWrap() needs to return Java.Lang.Object . However, the method
Oauth.Signpost.Basic.HttpURLConnectionRequestAdapter.UnWrap() has a return type of HttpURLConnection . There are
two ways to fix this issue:
Add a partial class declaration for HttpURLConnectionRequestAdapter and explicitly implement
IHttpRequest.Unwrap() :
namespace Oauth.Signpost.Basic {
partial class HttpURLConnectionRequestAdapter {
Java.Lang.Object OauthSignpost.Http.IHttpRequest.Unwrap() {
return Unwrap();
}
}
}
Remove the covariance from the generated C# code. This involves adding the following transform to
Transforms\Metadata.xml which will cause the generated C# code to have a return type of
Java.Lang.Object :
<attr
path="/api/package[@name='oauth.signpost.basic']/class[@name='HttpURLConnectionRequestAdapter']/method[@
name='unwrap']"
name="managedReturn">Java.Lang.Object
</attr>
Java.Lang.JavaSystem.LoadLibrary("pocketsphinx_jni");
Summary
In this article, we listed common troubleshooting issues associated with Java Bindings and explained how to
resolve them.
Related Links
Library Projects
Working with JNI
Enable Diagnostic Output
Xamarin for Android Developers
JD -GUI
Using Native Libraries
4/12/2018 • 2 minutes to read • Edit Online
Xamarin.Android supports the use of native libraries via the standard PInvoke mechanism. You can also bundle
additional native libraries which are not part of the OS into your .apk.
To deploy a native library with a Xamarin.Android application, add the library binary to the project and set its
Build Action to AndroidNativeLibrary.
To deploy a native library with a Xamarin.Android library project, add the library binary to the project and set its
Build Action to EmbeddedNativeLibrary.
Note that since Android supports multiple Application Binary Interfaces (ABIs), Xamarin.Android must know
which ABI the native library is built for. There are two ways this can be done:
1. Path "sniffing"
2. By using an AndroidNativeLibrary/Abi element within the project file
With path sniffing, the parent directory name of the native library is used to specify the ABI that the library targets.
Thus, if you add lib/armeabi/libfoo.so to the project, then the ABI will be "sniffed" as armeabi .
Alternatively, you can edit your project file to explicitly specify the ABI to use:
<ItemGroup>
<AndroidNativeLibrary Include="path/to/libfoo.so">
<Abi>armeabi</Abi>
</AndroidNativeLibrary>
</ItemGroup>
For more information about using native libraries, see Interop with native libraries.
Related Links
SanAngeles_NativeDebug (sample)
An Introduction to Renderscript
7/25/2018 • 7 minutes to read • Edit Online
This guide introduces Renderscript and explains how to use the intrinsic Renderscript API's in a Xamarin.Android
application that targets API level 17 or higher.
Overview
Renderscript is a programming framework created by Google for the purpose of improving the performance of
Android applications that require extensive computational resources. It is a low level, high performance API based
on C99. Because it is a low level API that will run on CPUs, GPUs, or DSPs, Renderscript is well suited for Android
apps that may need to perform any of the following:
Graphics
Image Processing
Encryption
Signal Processing
Mathematical Routines
Renderscript will use clang and compile the scripts to LLVM byte code which is bundled into the APK. When the
app is run for the first time, the LLVM byte code will be compiled into machine code for the processors on the
device. This architecture allows an Android application to exploit the advantages of machine code without the
developers themselves having to write it for each processor on the device themselves.
There are two components to a Renderscript routine:
1. The Renderscript runtime – This is the native APIs that are responsible for executing the Renderscript.
This includes any Renderscripts written for the application.
2. Managed Wrappers from the Android Framework – Managed classes that allow an Android app to
control and interact with the Renderscript runtime and scripts. In addition to the framework provided
classes for controlling the Renderscript runtime, the Android toolchain will examine the Renderscript source
code and generate managed wrapper classes for use by the Android application.
The following diagram illustrates how these components relate:
There are three important concepts for using Renderscripts in an Android application:
1. A context – A managed API provided by the Android SDK that allocates resources to Renderscript and
allows the Android app to pass and receive data from the Renderscript.
2. A compute kernel – Also known as the root kernel or kernel, this a routine that does the work. The kernel is
very similar to a C function; it is a parallelizable routine that will be run over all the data in allocated
memory .
3. Allocated Memory – Data is passed to and from a kernel through an Allocation. A kernel may have one
input and/or one output Allocation.
The Android.Renderscripts namespace contains the classes for interacting with the Renderscript runtime. In
particular, the Renderscript class will manage the lifecycle and resources of the Renderscript engine. The Android
app must initialize one or more Android.Renderscripts.Allocation objects. An Allocation is a managed API that is
responsible for allocation and accessing the memory that is shared between the Android app and the Renderscript
runtime. Typically, one Allocation is created for input, and optionally another Allocation is created to hold the
output of the kernel. The Renderscript runtime engine and the associated managed wrapper classes will manage
access to the memory held by the Allocations, there is no need for an Android app developer to do any extra work.
An Allocation will contain one or more Android.Renderscripts.Elements. Elements are a specialized type that
describe data in each Allocation. The Element types of the output Allocation must match the the types of the input
Element. When executing, a Renderscript will iterate over each Element in the input Allocation in parallel, and write
the results to the output Allocation. There are two types of Elements:
simple type – Conceptually this is the same as a C data type, float or a char .
complex type – This type is similar to a C struct .
The Renderscript engine will perform a runtime check to ensure that the Elements in each Allocation are
compatible with what is required by the kernel. If the data type of the Elements in the Allocation do not match the
data type that the kernel is expecting, an exception will be thrown.
All Renderscript kernels will be wrapped by a type that is a descendant of the Android.Renderscripts.Script class.
The Script class is used to set parameters for a Renderscript, set the appropriate Allocations , and run the
Renderscript. There are two Script subclasses in the Android SDK:
Android.Renderscripts.ScriptIntrinsic – Some of the more common Renderscript tasks are bundled in the
Android SDK and are accessible by a subclass of the ScriptIntrinsic class. There is no need for a developer
take any extra steps to use these scripts in their application as they are already provided.
ScriptC_XXXXX – Also known as user scripts, these are scripts that are written by developers and packaged in
the APK. At compile time, the Android toolchain will generate managed wrapper classes that will allow the
scripts to be used in the Android app. The name of these generated classes is the name of the Renderscript
file, prefixed with ScriptC_ . Writing and incorporating user scripts is not officially supported by
Xamarin.Android and beyond the scope of this guide.
Of these two types, only the StringIntrinsic is supported by Xamarin.Android. This guide will discuss how to use
intrinsic scripts in a Xamarin.Android application.
Requirements
This guide is for Xamarin.Android applications that target API level 17 or higher. The use of user scripts is not
covered in this guide.
The Xamarin.Android V8 Support Library backports the instrinsic Renderscript API's for apps that target older
versions of the Android SDK. Adding this package to a Xamarin.Android project should allow apps that target
older versions of the Android SDK to leverage the intrinsic scripts.
Create Allocations – Depending on the intrinsic script, it may be necessary to create one or two Allocation s.
The Android.Renderscripts.Allocation class has several factory methods to help with instantiating an allocation for
an intrinsic. As an example, the following code snippet demonstrates how to create Allocation for Bitmaps.
Android.Graphics.Bitmap originalBitmap;
Android.Renderscripts.Allocation inputAllocation = Allocation.CreateFromBitmap(renderScript,
originalBitmap,
Allocation.MipmapControl.MipmapFull,
AllocationUsage.Script);
Often, it will be necessary to create an Allocation to hold the output data of a script. This following snippet shows
how to use the Allocation.CreateTyped helper to instantiate a second Allocation that the same type as the
original:
Instantiate the Script wrapper – Each of the intrinsic script wrapper classes should have helper methods
(typically called Create )for instantiating a wrapper object for that script. The following code snippet is an example
of how to instantiate a ScriptIntrinsicBlur blur object. The Element.U8_4 helper method will create an Element
that describes a data type that is 4 fields of 8-bit, unsigned integer values, suitable for holding the data of a Bitmap
object:
Assign Allocation(s), Set Parameters, & Run Script – The Script class provides a ForEach method to actually
run the Renderscript. This method will iterate over each Element in the Allocation holding the input data. In
some cases, it may be necessary to provide an Allocation that holds the output. ForEach will overwrite the
contents of the output Allocation. To carry on with the code snippets from the previous steps, this example shows
how to assign an input Allocation, set a parameter, and then finally run the script (copying the results to the output
Allocation):
blurScript.SetInput(inputAllocation);
blurScript.SetRadius(25); // Set a pamaeter
blurScript.ForEach(outputAllocation);
You may wish to check out the Blur an Image with Renderscript recipe, it is a complete example of how to use an
intrinsic script in Xamarin.Android.
Summary
This guide introduced Renderscript and how to use it in a Xamarin.Android application. It briefly discussed what
Renderscript is and how it works in an Android application. It described some of the key components in
Renderscript and the difference between user scripts and instrinsic scripts. Finally, this guide discussed the steps in
using an intrinsic script in a Xamarin.Android application.
Related Links
Android.Renderscripts namespace
Blur an Image with Renderscript
Renderscript
Tutorial: Getting Started with Renderscript
Xamarin.Essentials
6/28/2018 • 2 minutes to read • Edit Online
Xamarin.Essentials provides developers with cross-platform APIs for their mobile applications.
Android, iOS, and UWP offer unique operating system and platform APIs that developers have access to all in C#
leveraging Xamarin. Xamarin.Essentials provides a single cross-platform API that works with any Xamarin.Forms,
Android, iOS, or UWP application that can be accessed from shared code no matter how the user interface is
created.
Feature Guides
Follow the guides to integrate these Xamarin.Essentials features into your applications:
Accelerometer – Retrieve acceleration data of the device in three dimensional space.
App Information – Find out information about the application.
Battery – Easily detect battery level, source, and state
Clipboard – Quickly and easily set or read text on the clipboard.
Compass – Monitor compass for changes.
Connectivity – Check connectivity state and detect changes.
Data Transfer – Send text and website uris to other apps.
Device Display Information – Get the device's screen metrics and orientation.
Device Information – Find out about the device with ease.
Email – Easily send email messages.
File System Helpers – Easily save files to app data.
Flashlight – A simple way to turn the flashlight on/off.
Geocoding – Geocode and reverse geocode addresses and coordinates.
Geolocation – Retrieve the device's GPS location.
Gyroscope – Track rotation around the device's three primary axes.
Magnetometer – Detect device's orientation relative to Earth's magnetic field.
MainThread – Run code on the application's main thread.
Open Browser – Quickly and easily open a browser to a specific website.
Orientation Sensor – Retrieve the orientation of the device in three dimensional space.
Phone Dialer – Open the phone dialer.
Power – Obtain the device's energy-saver status.
Preferences – Quickly and easily add persistent preferences.
Screen Lock – Keep the device screen awake.
Secure Storage – Securely store data.
SMS – Create an SMS message for sending.
Text-to-Speech – Vocalize text on the device.
Version Tracking – Track the applications version and build numbers.
Vibrate – Make the device vibrate.
Troubleshooting
Find help if you are running into issues.
API Documentation
Browse the API documentation for every feature of Xamarin.Essentials.
Get Started with Xamarin.Essentials
7/5/2018 • 2 minutes to read • Edit Online
Xamarin.Essentials provides a single cross-platform API that works with any iOS, Android, or UWP application
that can be accessed from shared code no matter how the user interface is created.
Platform Support
Xamarin.Essentials supports the following platforms and operating systems:
PLATFORM VERSION
Installation
Xamarin.Essentials is available as a NuGet package that can be added to any existing or new project using Visual
Studio.
1. Download and install Visual Studio with the Visual Studio tools for Xamarin.
2. Open an existing project, or create a new project using the Blank App template under Visual Studio C#
(Android, iPhone & iPad, or Cross-Platform). Important: If adding to a UWP project ensure Build 16299 or
higher is set in the project properties.
3. Add the Xamarin.Essentials NuGet package to each project:
Visual Studio
Visual Studio for Mac
In the Solution Explorer panel, right click on the solution name and select Manage NuGet Packages.
Search for Xamarin.Essentials and install the package into ALL projects including Android, iOS, UWP, and
.NET Standard libraries.
TIP
Check the Include prerelease box while the Xamarin.Essentials NuGet is in preview.
using Xamarin.Essentials;
5. Xamarin.Essentials requires platform-specific setup:
Android
iOS
UWP
Xamarin.Essentials supports a minimum Android version of 4.4, corresponding to API level 19, but the
target Android version for compiling must be 8.1, corresponding to API level 27. (In Visual Studio, these
two versions are set in the Project Properties dialog for the Android project, in the Android Manifest tab. In
Visual Studio for Mac, they're set in the Project Options dialog for the Android project, in the Android
Application tab.)
Xamarin.Essentials installs version 27.0.2.1 of the Xamarin.Android.Support libraries that it requires. Any
other Xamarin.Android.Support libraries that your application requires should also be updated to version
27.0.2.1 using the NuGet package manager. All Xamarin.Android.Support libraries used by your application
should be the same, and should be at least version 27.0.2.1. Refer to the troubleshooting page if you have
issues adding the Xamarin.Essentials NuGet or updating NuGets in your solution.
In the Android project's MainLauncher or any Activity that is launched Xamarin.Essentials must be
initialized in the OnCreate method:
Xamarin.Essentials.Platform.Init(this, bundle);
6. Follow the Xamarin.Essentials guides that enable you to copy and paste code snippets for each feature.
Other Resources
We recommend developers new to Xamarin visit Getting Started with Xamarin Development.
Visit the Xamarin.Essentials GitHub Respository to see the current source code, what is coming next, run samples,
and close the repository. Community contributions are welcome!
Browse through the API documentation for every feature of Xamarin.Essentials.
Xamarin.Essentials: Accelerometer
7/10/2018 • 2 minutes to read • Edit Online
The Accelerometer class lets you monitor the device's accelerometer sensor which indicates the acceleration of
the device in three dimensional space.
Using Accelerometer
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The Accelerometer functionality works by calling the Start and Stop methods to listen for changes to the
acceleration. Any changes are sent back through the ReadingChanged event. Here is sample usage:
public class AccelerometerTest
{
// Set speed delay for monitoring changes.
SensorSpeed speed = SensorSpeed.Ui;
public AccelerometerTest()
{
// Register for reading changes, be sure to unsubscribe when finished
Accelerometer.ReadingChanged += Accelerometer_ReadingChanged;
}
void Accelerometer_ReadingChanged(AccelerometerChangedEventArgs e)
{
var data = e.Reading;
Console.WriteLine($"Reading: X: {data.Acceleration.X}, Y: {data.Acceleration.Y}, Z:
{data.Acceleration.Z}");
// Process Acceleration X, Y, and Z
}
Accelerometer readings are reported back in G. A G is a unit of gravitation force equal to that exerted by the
earth's gravitational field (9.81 m/s^2).
The coordinate-system is defined relative to the screen of the phone in its default orientation. The axes are not
swapped when the device's screen orientation changes.
The X axis is horizontal and points to the right, the Y axis is vertical and points up and the Z axis points towards the
outside of the front face of the screen. In this system, coordinates behind the screen have negative Z values.
Examples:
When the device lies flat on a table and is pushed on its left side toward the right, the x acceleration value is
positive.
When the device lies flat on a table, the acceleration value is +1.00 G or (+9.81 m/s^2), which correspond
to the acceleration of the device (0 m/s^2) minus the force of gravity (-9.81 m/s^2) and normalized as in G.
When the device lies flat on a table and is pushed toward the sky with an acceleration of A m/s^2, the
acceleration value is equal to A+9.81 which correspond to the acceleration of the device (+A m/s^2) minus
the force of gravity (-9.81 m/s^2) and normalized in G.
Sensor Speed
Fastest – Get the sensor data as fast as possible (not guaranteed to return on UI thread).
Game – Rate suitable for games (not guaranteed to return on UI thread).
Normal – Default rate suitable for screen orientation changes.
Ui – Rate suitable for general user interface.
If your event handler is not guaranteed to run on the UI thread, and if the event handler needs to access user-
interface elements, use the MainThread.BeginInvokeOnMainThread method to run that code on the UI thread.
API
Accelerometer source code
Accelerometer API documentation
Xamarin.Essentials: App Information
6/28/2018 • 2 minutes to read • Edit Online
Using AppInfo
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
// Application Name
var appName = AppInfo.Name;
This settings page allows the user to change application permissions and perform other platform-specific tasks.
API
AppInfo source code
AppInfo API documentation
Xamarin.Essentials: Battery
7/5/2018 • 2 minutes to read • Edit Online
The Battery class lets you check the device's battery information and monitor for changes.
Getting Started
To access the Battery functionality the following platform specific setup is required.
Android
iOS
UWP
The Battery permission is required and must be configured in the Android project. This can be added in the
following ways:
Open the AssemblyInfo.cs file under the Properties folder and add:
[assembly: UsesPermission(Android.Manifest.Permission.Battery)]
Or right click on the Anroid project and open the project's properties. Under Android Manifest find the Required
permissions: area and check the Battery permission. This will automatically update the AndroidManifest.xml
file.
Using Battery
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
switch (state)
{
case BatteryState.Charging:
// Currently charging
break;
case BatteryState.Full:
// Battery is full
break;
case BatteryState.Discharging:
case BatteryState.NotCharging:
// Currently discharging battery or not being charged
break;
case BatteryState.NotPresent:
// Battery doesn't exist in device (desktop computer)
case BatteryState.Unknown:
// Unable to detect battery state
break;
}
switch (source)
{
case BatteryPowerSource.Battery:
// Being powered by the battery
break;
case BatteryPowerSource.Ac:
// Being powered by A/C unit
break;
case BatteryPowerSource.Usb:
// Being powered by USB cable
break;
case BatteryPowerSource.Wireless:
// Powered via wireless charging
break;
case BatteryPowerSource.Unknown:
// Unable to detect power source
break;
}
void Battery_BatteryChanged(BatteryChangedEventArgs e)
{
var level = e.ChargeLevel;
var state = e.State;
var source = e.PowerSource;
Console.WriteLine($"Reading: Level: {level}, State: {state}, Source: {source}");
}
}
Platform Differences
Android
iOS
UWP
No platform differences.
API
Battery source code
Battery API documentation
Xamarin.Essentials: Clipboard
6/5/2018 • 2 minutes to read • Edit Online
The Clipboard class lets you copy and paste text to the system clipboard between applications.
Using Clipboard
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
Clipboard.SetText("Hello World");
API
Clipboard source code
Clipboard API documentation
Xamarin.Essentials: Compass
7/10/2018 • 2 minutes to read • Edit Online
The Compass class lets you monitor the device's magnetic north heading.
Using Compass
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The Compass functionality works by calling the Start and Stop methods to listen for changes to the compass.
Any changes are sent back through the ReadingChanged event. Here is an example:
public CompassTest()
{
// Register for reading changes, be sure to unsubscribe when finished
Compass.ReadingChanged += Compass_ReadingChanged;
}
void Compass_ReadingChanged(CompassChangedEventArgs e)
{
var data = e.Reading;
Console.WriteLine($"Reading: {data.HeadingMagneticNorth} degrees");
// Process Heading Magnetic North
}
API
Compass source code
Compass API documentation
Xamarin.Essentials: Connectivity
6/5/2018 • 2 minutes to read • Edit Online
The Connectivity class lets you monitor for changes in the device's network conditions, check the current network
access, and how it is currently connected.
Getting Started
To access the Connectivity functionality the following platform specific setup is required.
Android
iOS
UWP
The AccessNetworkState permission is required and must be configured in the Android project. This can be added
in the following ways:
Open the AssemblyInfo.cs file under the Properties folder and add:
[assembly: UsesPermission(Android.Manifest.Permission.AccessNetworkState)]
Or right click on the Anroid project and open the project's properties. Under Android Manifest find the Required
permissions: area and check the Access Network State permission. This will automatically update the
AndroidManifest.xml file.
Using Connectivity
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
if (current == NetworkAccess.Internet)
{
// Connection to internet is available
}
Whenever the connection profile or network access changes you can receive an event when triggered:
void Connectivity_ConnectivityChanged(ConnectivityChangedEventArgs e)
{
var access = e.NetworkAccess;
var profiles = e.Profiles;
}
}
Limitations
It is important to note that it is possible that Internet is reported by NetworkAccess but full access to the web is
not available. Due to how connectivity works on each platform it can only guarantee that a connection is available.
For instance the device may be connected to a Wi-Fi network, but the router is disconnected from the internet. In
this instance Internet may be reported, but an active connection is not available.
API
Connectivity source code
Connectivity API documentation
Xamarin.Essentials: Data Transfer
7/5/2018 • 2 minutes to read • Edit Online
The DataTransfer class enables an application to share data such as text and web links to other applications on the
device.
using Xamarin.Essentials;
The Data Transfer functionality works by calling the RequestAsync method with a data request payload that
includes information to share to other applications. Text and Uri can be mixed and each platform will handle
filtering based on content.
User interface to share to external application that appears when request is made:
Platform Differences
Android
iOS
UWP
Subject property is used for desired subject of a message.
API
Data Transfer source code
Data Transfer API documentation
Xamarin.Essentials: Device Display Information
6/28/2018 • 2 minutes to read • Edit Online
The DeviceDisplay class provides information about the device's screen metrics the application is running on.
Using DeviceDisplay
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
Screen Metrics
In addition to basic device information the DeviceDisplay class contains information about the device's screen
and orientation.
// Get Metrics
var metrics = DeviceDisplay.ScreenMetrics;
// Screen density
var density = metrics.Density;
The DeviceDisplay class also exposes an event that can be subscribed to that is triggered whenever any screen
metric changes:
public class ScreenMetricsTest
{
public ScreenMetricsTest()
{
// Subscribe to changes of screen metrics
DeviceDisplay.ScreenMetricsChanaged += OnScreenMetricsChanged;
}
void OnScreenMetricsChanged(ScreenMetricsChangedEventArgs e)
{
// Process changes
var metrics = e.Metrics;
}
}
API
DeviceDisplay source code
DeviceDisplay API documentation
Xamarin.Essentials: Device Information
6/5/2018 • 2 minutes to read • Edit Online
The DeviceInfo class provides information about the device the application is running on.
Using DeviceInfo
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
// Manufacturer (Samsung)
var manufacturer = DeviceInfo.Manufacturer;
// Platform (Android)
var platform = DeviceInfo.Platform;
// Idiom (Phone)
var idiom = DeviceInfo.Idiom;
Platforms
DeviceInfo.Platform correlates to a constant string that maps to the operating system. The values can be checked
with the Platforms class:
DeviceInfo.Platforms.iOS – iOS
DeviceInfo.Platforms.Android – Android
DeviceInfo.Platforms.UWP – UWP
DeviceInfo.Platforms.Unsupported – Unsupported
Idioms
DeviceInfo.Idiom correlates a constant string that maps to the type of device the application is running on. The
values can be checked with the Idioms class:
DeviceInfo.Idioms.Phone – Phone
DeviceInfo.Idioms.Tablet – Tablet
DeviceInfo.Idioms.Desktop – Desktop
DeviceInfo.Idioms.TV – TV
DeviceInfo.Idioms.Unsupported – Unsupported
Device Type
DeviceInfo.DeviceType correlates an enumeration to determine if the application is runing on a physical or vitual
device. A virtual device is a simulator or emulator.
API
DeviceInfo source code
DeviceInfo API documentation
Xamarin.Essentials: Email
6/5/2018 • 2 minutes to read • Edit Online
The Email class enables an application to open the default email application with a specified information including
subject, body, and recepients (TO, CC, BCC ).
Using Email
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The Email functionality works by calling the ComposeAsync method an EmailMessage that contains information
about the email:
await Email.ComposeAsync(message);
}
catch (FeatureNotSupportedException fbsEx)
{
// Email is not supported on this device
}
catch (Exception ex)
{
// Some other exception occured
}
}
}
API
Email source code
Email API documentation
Xamarin.Essentials: File System Helpers
6/5/2018 • 2 minutes to read • Edit Online
The FileSystem class contains a series of helpers to find the application's cache and data directories and open
files inside of the app package.
using Xamarin.Essentials;
To get the application's directory to store cache data. Cache data can be used for any data that needs to persist
longer than temporary data, but should not be data that is required to properly operate.
To get the application's top-level directory for any files that are not user data files. These files are backed up with
the operating system syncing framework. See Platform Implementation Specifics below.
The Flashlight class has the ability to turn on or off the device's camera flash to turn it into a flashlight.
Getting Started
To access the Flashlight functionality the following platform specific setup is required.
Android
iOS
UWP
The Flashlight and Camera permissions are required and must be configured in the Android project. This can be
added in the following ways:
Open the AssemblyInfo.cs file under the Properties folder and add:
[assembly: UsesPermission(Android.Manifest.Permission.Flashlight)]
[assembly: UsesPermission(Android.Manifest.Permission.Camera)]
Or right click on the Anroid project and open the project's properties. Under Android Manifest find the Required
permissions: area and check the FLASHLIGHT and CAMERA permissions. This will automatically update the
AndroidManifest.xml file.
By adding these permissions Google Play will automatically filter out devices without specific hardware. You can
get around this by adding the following to your AssemblyInfo.cs file in your Android project:
Using Flashlight
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The flashlight can be turned on and off through the TurnOnAsync and TurnOffAsync methods:
try
{
// Turn On
await Flashlight.TurnOnAsync();
// Turn Off
await Flashlight.TurnOffAsync();
}
catch (FeatureNotSupportedException fnsEx)
{
// Handle not supported on device exception
}
catch (PermissionException pEx)
{
// Handle permission exception
}
catch (Exception ex)
{
// Unable to turn on/off flashlight
}
API
Flashlight source code
Flashlight API documentation
Xamarin.Essentials: Geocoding
6/28/2018 • 2 minutes to read • Edit Online
The Geocoding class provides APIs to geocode a placemark to a positional coordinates and reverse geocode
coordincates to a placemark.
Getting Started
To access the Geocoding functionality the following platform specific setup is required.
Android
iOS
UWP
No additional setup required.
Using Geocoding
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
try
{
var address = "Microsoft Building 25 Redmond WA USA";
var locations = await Geocoding.GetLocationsAsync(address);
The altitude isn't always available. If it is not available, the Altitude property might be null or the value might be
zero. If the altitude is available, the value is in meters above above sea level.
Getting placemarks for an existing set of coordinates:
try
{
var lat = 47.673988;
var lon = -122.121513;
Console.WriteLine(geocodeAddress);
}
}
catch (FeatureNotSupportedException fnsEx)
{
// Feature not supported on device
}
catch (Exception ex)
{
// Handle exception that may have occurred in geocoding
}
API
Geocoding source code
Geocoding API documentation
Xamarin.Essentials: Geolocation
6/28/2018 • 3 minutes to read • Edit Online
The Geolocation class provides APIs to retrieve the device's current geolocation coordinates.
Getting Started
To access the Geolocation functionality, the following platform-specific setup is required:
Android
iOS
UWP
Coarse and Fine Location permissions are required and must be configured in the Android project. Additionally, if
your app targets Android 5.0 (API level 21) or higher, you must declare that your app uses the hardware features in
the manifest file. This can be added in the following ways:
Open the AssemblyInfo.cs file under the Properties folder and add:
[assembly: UsesPermission(Android.Manifest.Permission.AccessCoarseLocation)]
[assembly: UsesPermission(Android.Manifest.Permission.AccessFineLocation)]
[assembly: UsesFeature("android.hardware.location", Required = false)]
[assembly: UsesFeature("android.hardware.location.gps", Required = false)]
[assembly: UsesFeature("android.hardware.location.network", Required = false)]
Or right-click on the Android project and open the project's properties. Under Android Manifest find the
Required permissions: area and check the ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION
permissions. This will automatically update the AndroidManifest.xml file.
Using Geolocation
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The Geoloation API will also prompt the user for permissions when necessary.
You can get the last known location of the device by calling the GetLastKnownLocationAsync method. This is often
faster then doing a full query, but can be less accurate.
try
{
var location = await Geolocation.GetLastKnownLocationAsync();
if (location != null)
{
Console.WriteLine($"Latitude: {location.Latitude}, Longitude: {location.Longitude}, Altitude:
{location.Altitude}");
}
}
catch (FeatureNotSupportedException fnsEx)
{
// Handle not supported on device exception
}
catch (PermissionException pEx)
{
// Handle permission exception
}
catch (Exception ex)
{
// Unable to get location
}
The altitude isn't always available. If it is not available, the Altitude property might be null or the value might be
zero. If the altitude is available, the value is in meters above above sea level.
To query the current device's location coordinates, the GetLocationAsync can be used. It is best to pass in a full
GeolocationRequest and CancellationToken since it may take some time to get the device's location.
try
{
var request = new GeolocationRequest(GeolocationAccuracy.Medium);
var location = await Geolocation.GetLocationAsync(request);
if (location != null)
{
Console.WriteLine($"Latitude: {location.Latitude}, Longitude: {location.Longitude}, Altitude:
{location.Altitude}");
}
}
catch (FeatureNotSupportedException fnsEx)
{
// Handle not supported on device exception
}
catch (PermissionException pEx)
{
// Handle permission exception
}
catch (Exception ex)
{
// Unable to get location
}
Geolocation Accuracy
The following table outlines accuracy per platform:
Lowest
PLATFORM DISTANCE (IN METERS)
Android 500
iOS 3000
Low
PLATFORM DISTANCE (IN METERS)
Android 500
iOS 1000
Medium (default)
PLATFORM DISTANCE (IN METERS)
iOS 100
UWP 30-500
High
PLATFORM DISTANCE (IN METERS)
Android 0 - 100
iOS 10
UWP <= 10
Best
PLATFORM DISTANCE (IN METERS)
Android 0 - 100
iOS ~0
UWP <= 10
The Location constructor has latitude and longitude arguments in that order. Positive latitude values are north of
the equator, and positive longitude values are east of the Prime Meridian. Use the final argument to
CalculateDistance to specify miles or kilometers. The Location class also defines KilometersToMiles and
MilesToKilometers methods for converting between the two units.
API
Geolocation source code
Geolocation API documentation
Xamarin.Essentials: Gyroscope
7/10/2018 • 2 minutes to read • Edit Online
The Gyroscope class lets you monitor the device's gyroscope sensor which is the rotation around the device's
three primary axes.
Using Gyroscope
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The Gyroscope functionality works by calling the Start and Stop methods to listen for changes to the gyroscope.
Any changes are sent back through the ReadingChanged event. Here is sample usage:
public class GyroscopeTest
{
// Set speed delay for monitoring changes.
SensorSpeed speed = SensorSpeed.Ui;
public GyroscopeTest()
{
// Register for reading changes.
Gyroscope.ReadingChanged += Gyroscope_ReadingChanged;
}
void Gyroscope_ReadingChanged(GyroscopeChangedEventArgs e)
{
var data = e.Reading;
// Process Angular Velocity X, Y, and Z
Console.WriteLine($"Reading: X: {data.AngularVelocity.X}, Y: {data.AngularVelocity.Y}, Z:
{data.AngularVelocity.Z}");
}
Sensor Speed
Fastest – Get the sensor data as fast as possible (not guaranteed to return on UI thread).
Game – Rate suitable for games (not guaranteed to return on UI thread).
Normal – Default rate suitable for screen orientation changes.
Ui – Rate suitable for general user interface.
If your event handler is not guaranteed to run on the UI thread, and if the event handler needs to access user-
interface elements, use the MainThread.BeginInvokeOnMainThread method to run that code on the UI thread.
API
Gyroscope source code
Gyroscope API documentation
Xamarin.Essentials: Magnetometer
7/10/2018 • 2 minutes to read • Edit Online
The Magnetometer class lets you monitor the device's magnetometer sensor which indicates the device's
orientation relative to Earth's magnetic field.
Using Magnetometer
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The Magnetometer functionality works by calling the Start and Stop methods to listen for changes to the
magnetometer. Any changes are sent back through the ReadingChanged event. Here is sample usage:
public class MagnetometerTest
{
// Set speed delay for monitoring changes.
SensorSpeed speed = SensorSpeed.Ui;
public MagnetometerTest()
{
// Register for reading changes.
Magnetometer.ReadingChanged += Magnetometer_ReadingChanged;
}
void Magnetometerr_ReadingChanged(MagnetometerChangedEventArgs e)
{
var data = e.Reading;
// Process MagneticField X, Y, and Z
Console.WriteLine($"Reading: X: {data.MagneticField.X}, Y: {data.MagneticField.Y}, Z:
{data.MagneticField.Z}");
}
Sensor Speed
Fastest – Get the sensor data as fast as possible (not guaranteed to return on UI thread).
Game – Rate suitable for games (not guaranteed to return on UI thread).
Normal – Default rate suitable for screen orientation changes.
Ui – Rate suitable for general user interface.
If your event handler is not guaranteed to run on the UI thread, and if the event handler needs to access user-
interface elements, use the MainThread.BeginInvokeOnMainThread method to run that code on the UI thread.
API
Magnetometer source code
Magnetometer API documentation
Xamarin.Essentials: MainThread
6/28/2018 • 2 minutes to read • Edit Online
The MainThread class allows applications to run code on the main thread of execution, and to determine if a
particular block of code is currently running on the main thread.
Background
Most operating systems — including iOS, Android, and the Universal Windows Platform — use a single-
threading model for code involving the user interface. This model is necessary to properly serialize user-interface
events, including keystrokes and touch input. This thread is often called the main thread or the user-interface
thread or the UI thread. The disadvantage of this model is that all code that accesses user interface elements must
run on the application's main thread.
Applications sometimes need to use events that call the event handler on a secondary thread of execution. (The
Xamarin.Essentials classes Accelerometer , Compass , Gyroscope , Magnetometer , and OrientationSensor all might
return information on a secondary thread when used with faster speeds.) If the event handler needs to access
user-interface elements, it must run that code on the main thread. The MainThread class allows the application
to run this code on the main thread.
using Xamarin.Essentials;
To run code on the main thread, call the static MainThread.BeginInvokeOnMainThread method. The argument is an
Action object, which is simply a method with no arguments and no return value:
MainThread.BeginInvokeOnMainThread(() =>
{
// Code to run on the main thread
});
It is also possible to define a separate method for the code that must run on the main thread:
void MyMainThreadCode()
{
// Code to run on the main thread
}
You can then run this method on the main thread by referencing it in the BeginInvokeOnMainThread method:
MainThread.BeginInvokeOnMainThread(MyMainThreadCode);
NOTE
Xamarin.Forms has a method called Device.BeginInvokeOnMainThread(Action) that does the same thing as
MainThread.BeginInvokeOnMainThread(Action) . While you can use either method in a Xamarin.Forms app, consider
whether or not the calling code has any other need for a dependency on Xamarin.Forms. If not,
MainThread.BeginInvokeOnMainThread(Action) is likely a better option.
if (MainThread.IsMainThread)
{
// Code to run if this is the main thread
}
else
{
// Code to run if this is a secondary thread
}
You might wonder if you should check if code is running on a secondary thread before calling
BeginInvokeOnMainThread , for example, like this:
if (MainThread.IsMainThread)
{
MyMainThreadCode();
}
else
{
MainThread.BeginInvokeOnMainThread(MyMainThreadCode);
}
You might suspect that this check might improve performance if the block of code is already running on the main
thread.
However, this check is not necessary. The platform implementations of BeginInvokeOnMainThread themselves check
if the call is made on the main thread. There is very little performance penalty if you call BeginInvokeOnMainThread
when it's not really necessary.
API
MainThread source code
MainThread API documentation
Xamarin.Essentials: Browser
6/5/2018 • 2 minutes to read • Edit Online
The Browser class enables an application to open a web link in the optimized system preferred browser or the
external browser.
Using Browser
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The Browser functionality works by calling the OpenAsync method with the Uri and BrowserLaunchType .
System Preferred
Chrome Custom Tabs will attempted to be used load the Uri and keep navigation awareness.
External
An Intent will be used to request the Uri be opened through the systems normal browser.
API
Browser source code
Browser API documentation
Xamarin.Essentials: Browser
6/5/2018 • 2 minutes to read • Edit Online
The Browser class enables an application to open a web link in the optimized system preferred browser or the
external browser.
Using Browser
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The Browser functionality works by calling the OpenAsync method with the Uri and BrowserLaunchType .
System Preferred
Chrome Custom Tabs will attempted to be used load the Uri and keep navigation awareness.
External
An Intent will be used to request the Uri be opened through the systems normal browser.
API
Browser source code
Browser API documentation
Xamarin.Essentials: Phone Dialer
7/18/2018 • 2 minutes to read • Edit Online
The PhoneDialer class enables an application to open a phone number in the dialer.
using Xamarin.Essentials;
The Phone Dialer functionality works by calling the Open method with a phone number to open the dialer with.
When Open is requested the API will automatically attempt to format the number based on the country code if
specified.
API
Phone Dialer source code
Phone Dialer API documentation
Xamarin.Essentials: Power Energy Saver Status
6/28/2018 • 2 minutes to read • Edit Online
The Power class provides information about the device's energy-saver status, which indicates if the device is
running in a low -power mode. Applications should avoid background processing if the device's energy-saver status
is on.
Background
Devices that run on batteries can be put into a low -power energy-saver mode. Sometimes devices are switched
into this mode automatically, for example, when the battery drops below 20% capacity. The operating system
responds to energy-saver mode by reducing activities that tend to deplete the battery. Applications can help by
avoiding background processing or other high-power activities when energy-saver mode is on.
For Android devices, the Power class returns meaningful information only for Android version 5.0 (Lollipop) and
above.
using Xamarin.Essentials;
Obtain the current energy-saver status of the device using the static Power.EnergySaverStatus property:
This property returns a member of the EnergySaverStatus enumeration, which is either On , Off , or Unknown . If
the property returns On , the application should avoid background processing or other activities that might
consume a lot of power.
The application should also install an event handler. The Power class exposes an event that is triggered when the
energy-saver status changes:
public class EnergySaverTest
{
public EnergySaverTest()
{
// Subscribe to changes of energy-saver status
Power.EnergySaverStatusChanaged += OnEnergySaverStatusChanaged;
}
If the energy-saver status changes to On , the application should stop performing background processing. If the
status changes to Unknown or Off , the application can resume background processing.
API
Power source code
Power API documentation
Xamarin.Essentials: Preferences
7/3/2018 • 2 minutes to read • Edit Online
Using Preferences
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
Preferences.Set("my_key", "my_value");
Preferences.Remove("my_key");
Preferences.Clear();
In addition to these methods each take in an optional sharedName that can be used to create additional containers
for preference. Read the platform implementation specifics below.
Limitations
When storing a string, this API is intended to store small amounts of text. Performance may be subpar if you try to
use it to store large amounts of text.
API
Preferences source code
Preferences API documentation
Xamarin.Essentials: Screen Lock
6/5/2018 • 2 minutes to read • Edit Online
The ScreenLock class can request to keep the screen from falling asleep when the application is running.
Using ScreenLock
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The screen lock functionality works by calling the RequestActive and RequestRelease methods to request the
screen from turning off.
API
Screen Lock source code
Screen Lock API documentation
Xamarin.Essentials: Secure Storage
7/3/2018 • 2 minutes to read • Edit Online
Getting Started
To access the SecureStorage functionality, the following platform-specific setup is required:
Android
iOS
UWP
No additional setup required.
using Xamarin.Essentials;
NOTE
If there is no value associated with the requested key, GetAsync will return null .
SecureStorage.Remove("oauth_token");
SecureStorage.RemoveAll();
Platform Implementation Specifics
Android
iOS
UWP
The Android KeyStore is used to store the cipher key used to encrypt the value before it is saved into a Shared
Preferences with a filename of [YOUR-APP -PACKAGE -ID ].xamarinessentials. The key used in the shared
preferences file is a MD5 Hash of the key passed into the SecureStorage API's.
Limitations
This API is intended to store small amounts of text. Performance may be slow if you try to use it to store large
amounts of text.
API
SecureStorage source code
SecureStorage API documentation
Xamarin.Essentials: SMS
6/5/2018 • 2 minutes to read • Edit Online
The Sms class enables an application to open the default SMS application with a specified message to send to a
recipient.
Using Sms
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The SMS functionality works by calling the ComposeAsync method an SmsMessage that contains the message's
recipient and the body of the message, both of which are optional.
API
Sms source code
Sms API documentation
Xamarin.Essentials: Text-to-Speech
6/5/2018 • 2 minutes to read • Edit Online
The TextToSpeech class enables an application to utilize the built in text-to-speech engines to speak back text
from the device and also to query available languages that the engine can support.
Using Text-to-Speech
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The Text-to-Speech functionality works by calling the SpeakAsync method with text and optional parameters and
returns after the utterance has finished.
}, TaskScheduler.FromCurrentSynchronizationContext());
}
This method takes in an optional CancellationToken to stop the utterance once it starts.
CancellationTokenSource cts;
public async Task SpeakNowDefaultSettings()
{
cts = new CancellationTokenSource();
await TextToSpeech.SpeakAsync("Hello World", cancelToken: cts.Token);
cts.Cancel();
}
Text-to-Speech will automatically queue speech requests from the same thread.
Speech Settings
For more control over how the audio is spoken back with SpeakSettings that allows setting the Volume, Pitch, and
Locale.
Pitch 0 2.0
Volume 0 1.0
Speech Locales
Each platform offers locales to speak back text in multiple languages and accents. Each platform has different
codes and ways of specifying this, which is why Essentials provides a cross-platform Locale class and a way to
query them with GetLocalesAsync .
public async Task SpeakNow()
{
var locales = await TextToSpeech.GetLocalesAsync();
Limitations
Utterance queue is not guaranteed if called across multiple threads.
Background audio playback is not officially supported.
API
TextToSpeech source code
TextToSpeech API documentation
Xamarin.Essentials: Version Tracking
6/5/2018 • 2 minutes to read • Edit Online
The VersionTracking class lets you check the applications version and build numbers along with seeing additional
information such as if it is the first time the application launched ever or for the current version, get the previous
build information, and more.
using Xamarin.Essentials;
The first time you use the VersionTracking class it will start tracking the current version. You must call Track
early only in your application each time it is loaded to ensure the current version information is tracked:
VersionTracking.Track();
API
Version Tracking source code
Version Tracking API documentation
Xamarin.Essentials: Vibration
7/10/2018 • 2 minutes to read • Edit Online
The Vibration class lets you start and stop the vibrate functionality for a desired amount of time.
Getting Started
To access the Vibration functionality the following platform specific setup is required.
Android
iOS
UWP
The Vibrate permission is required and must be configured in the Android project. This can be added in the
following ways:
Open the AssemblyInfo.cs file under the Properties folder and add:
[assembly: UsesPermission(Android.Manifest.Permission.Vibrate)]
Or right click on the Anroid project and open the project's properties. Under Android Manifest find the Required
permissions: area and check the VIBRATE permission. This will automatically update the AndroidManifest.xml
file.
Using Vibration
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The Vibration functionality can be requested for a set amount of time or the default of 500 milliseconds.
try
{
// Use default vibration length
Vibration.Vibrate();
try
{
Vibration.Cancel();
}
catch (FeatureNotSupportedException ex)
{
// Feature not supported on device
}
catch (Exception ex)
{
// Other error has occurred.
}
Platform Differences
Android
iOS
UWP
No platform differences.
API
Vibration source code
Vibration API documentation
Xamarin.Essentials: Troubleshooting
7/10/2018 • 2 minutes to read • Edit Online
NU1107: Version conflict detected for Xamarin.Android.Support.Compat. Reference the package directly from the
project to resolve this issue.
MyApp -> Xamarin.Essentials 0.8.0-preview -> Xamarin.Android.Support.CustomTabs 27.0.2.1 ->
Xamarin.Android.Support.Compat (= 27.0.2.1)
MyApp -> Xamarin.Forms 3.1.0.583944 -> Xamarin.Android.Support.v4 25.4.0.2 -> Xamarin.Android.Support.Compat
(= 25.4.0.2).
The problem is mismatched dependencies for the two NuGets. This can be resolved by manually adding a specific
version of the dependency (in this case Xamarin.Android.Support.Compat) that can support both.
To do this, add the NuGet that is the source of the conflict manually, and use the Version list to select a specific
version. Currently version 27.0.2.1 of the Xamarin.Android.Support.Compat & Xamarin.Android.Support.Core.Util
NuGet will resolve this error.
Refer to this blog post for more information and a video on how to resolve the issue.
If run into any issues or find a bug please report it on the Xamarin.Essentials GitHub repository.
Data and Cloud Services
5/2/2018 • 2 minutes to read • Edit Online
Data Access
This section discusses data access in Xamarin.Android using SQLite as the database engine.
Google Messaging
Google provides both Firebase Cloud Messaging and legacy Google Cloud Messaging services for facilitating
messaging between mobile apps and server applications. This section provides overviews for each service
provided by step-by-step explanation of how to use these services to implement remote notifications (also called
push notifications) in Xamarin.Android applications.
Microsoft Azure Active Directory
6/5/2018 • 2 minutes to read • Edit Online
Azure Active Directory allows developers to secure resources such as files, links, and Web APIs, Office 365, and
more using the same organizational account that employees use to sign in to their systems or check their emails.
Getting Started
Follow the getting started instructions to configure the Azure portal and add Active Directory authentication to
your Xamarin apps.
1. Registering with Azure Active Directory on the windowsazure.com portal, then
2. Configure services.
3. Hook up one of the following:
Office 365
Once you have added Active Directory authentication to an app, you can also use the credentials to interact with
Office 365.
Graph API
Learn how to access the Graph API using Xamarin (also covered in our blog).
Azure Active Directory
6/5/2018 • 2 minutes to read • Edit Online
Conclusion
Using the steps above you can authenticate your mobile apps against Azure Active Directory. The Active Directory
Authentication Library (ADAL ) makes it much easier with fewer lines of code, while keeping most of the code the
same and thus making it shareable across platforms.
Related Links
Microsoft NativeClient sample
Step 1. Register an app to use Azure Active Directory
6/5/2018 • 2 minutes to read • Edit Online
1. Navigate to windowsazure.com and log in with your Microsoft Account or Organization Account in the
Azure Portal. If you don’t have an Azure subscription, you can get a trial from azure.com
2. After signing in, go to the Active Directory (1) section and choose the directory where you want to
register the application (2)
3. Click Add to create new application, then select Add an application my organization is developing
4. On the next screen, give your app a name (eg. XAM -DEMO ). Make sure you select Native Client Application
as the type of application.
5. On the final screen, provide a *Redirect URI that is unique to your application as it will return to this URI when
authentication is complete.
6. Once the app is created, navigate to the Configure tab. Write down the Client ID which we’ll use in our
application later. Also, on this screen you can give your mobile application access to Active Directory or add
another application like Web API or Office365, which can be used by mobile application once
authentication is complete.
Related Links
Microsoft NativeClient sample
Step 2. Configure Service Access for Mobile
Application
6/5/2018 • 2 minutes to read • Edit Online
Whenever any resource e.g. web application, web service, etc. needs to be secured by Azure Active Directory, it
needs to be registered. All the secure applications or services can be seen under Applications tab. Here you can
select the application which needs to be accessed from mobile application and give access to it.
1. On the Configure tab, locate permissions to other applications section:
2. Click on Add application button. On the next screen pop-up you should see list of all the applications which
are secured by Azure Active Directory. Select the applications that needs to be accessed from the mobile
application.
3. After selecting the application, once again select the newly-added application in permissions to other
applications section and give appropriate rights.
4. Finally, Save the configuration. These services should now be available in mobile applications!
Related Links
Microsoft NativeClient sample
Accessing the Graph API
6/5/2018 • 3 minutes to read • Edit Online
Follow these steps to use the Graph API from within a Xamarin application:
1. Registering with Azure Active Directory on the windowsazure.com portal, then
2. Configure services.
IMPORTANT
Note: Azure ADAL 3.0 is currently a preview and there may be breaking changes before the final version is released.
In your application, you will now need to add the following class level variables that are required for the
authentication flow.
//Client ID
public static string clientId = "25927d3c-.....-63f2304b90de";
public static string commonAuthority = "https://login.windows.net/common"
//Redirect URI
public static Uri returnUri = new Uri("http://xam-demo-redirect");
//Graph URI if you've given permission to Azure Active Directory
const string graphResourceUri = "https://graph.windows.net";
public static string graphApiVersion = "2013-11-08";
//AuthenticationResult will hold the result after authentication completes
AuthenticationResult authResult = null;
One thing to note here is commonAuthority . When the authentication endpoint is common , your app becomes
multi-tenant, which means any user can use login with their Active Directory credentials. After authentication,
that user will work on the context of their own Active Directory – i.e. they will see details related to his Active
Directory.
Write method to acquire Access Token
The following code (for Android) will start the authentication and upon completion assign the result in authResult
. The iOS and Windows Phone implementations differ slightly: the second parameter ( Activity ) is different on
iOS and absent on Windows Phone.
In the above code, the AuthenticationContext is responsible for the authentication with commonAuthority. It has
an AcquireTokenAsync method, which take parameters as a resource which needs to be accessed, in this case
graphResourceUri , clientId , and returnUri . The app will return to the returnUri when authentication
completes. This code will remain the same for all platforms, however, the last parameter, AuthorizationParameters ,
will be different on different platforms and is responsible for governing the authentication flow.
In the case of Android or iOS, we pass this parameter to AuthorizationParameters(this) to share the context,
whereas in Windows it is passed without any parameter as new AuthorizationParameters() .
Handle continuation for Android
After authentication is complete, the flow should return to the app. In the case of Android it is handled by
following code, which should be added to MainActivity.cs:
Now if you run the application, you should see an authentication dialog. Upon successful authentication, it will ask
your permissions to access the resources (in our case Graph API):
If authentication is successful and you’ve authorized the app to access the resources, you should get an
AccessToken and RefreshToken combo in authResult . These tokens are required for further API calls and for
authorization with Azure Active Directory behind the scenes.
For example, the code below allows you to get a user list from Active Directory. You can replace the Web API URL
with your Web API which is protected by Azure AD.
Getting Started
This article provides step-by-step instructions to get your first Xamarin Azure app up and running. It covers
creating a new Azure Mobile App in the portal and then downloading and running the pre-configured app.
iOS
Android
Xamarin.Forms
Most applications have some requirement to save data on the device locally. Unless the amount of data is trivially
small, this usually requires a database and a data layer in the application to manage database access. Android has
the SQLite database engine 'built in' and access to store and retrieve data is simplified by Xamarin's platform. This
document shows how to access an SQLite database in a cross-platform way.
Related Links
DataAccess Basic (sample)
DataAccess Advanced (sample)
Android Data Recipes
Xamarin.Forms data access
Introduction
7/25/2018 • 3 minutes to read • Edit Online
Related Links
DataAccess Basic (sample)
DataAccess Advanced (sample)
Android Data Recipes
Xamarin.Forms data access
Configuration
7/25/2018 • 2 minutes to read • Edit Online
To use SQLite in your Xamarin.Android application you will need to determine the correct file location for your
database file.
There are other things to take into consideration when deciding where to store the database file. For example, on
Android you can choose whether to use internal or external storage.
If you wish to use a different location on each platform in your cross platform application you can use a compiler
directive as shown to generate a different path for each platform:
For hints on using the file system in Android, refer to the Browse Files recipe. See the Building Cross Platform
Applications document for more information on using compiler directives to write code specific to each platform.
Threading
You should not use the same SQLite database connection across multiple threads. Be careful to open, use and then
close any connections you create on the same thread.
To ensure that your code is not attempting to access the SQLite database from multiple threads at the same time,
manually take a lock whenever you are going to access the database, like this:
All database access (reads, writes, updates, etc) should be wrapped with the same lock. Care must be taken to avoid
a deadlock situation by ensuring that the work inside the lock clause is kept simple and does not call out to other
methods that may also take a lock!
Related Links
DataAccess Basic (sample)
DataAccess Advanced (sample)
Android Data Recipes
Xamarin.Forms data access
Using SQLite.NET with Android
5/31/2018 • 6 minutes to read • Edit Online
The SQLite.NET library that Xamarin recommends is a very basic ORM that lets you easily store and retrieve
objects in the local SQLite database on an Android device. ORM stands for Object Relational Mapping – an API
that lets you save and retrieve "objects" from a database without writing SQL statements.
To include the SQLite.NET library in a Xamarin app, add the following NuGet package to your project:
Package Name: sqlite-net-pcl
Author: Frank A. Krueger
Id: sqlite-net-pcl
Url: nuget.org/packages/sqlite-net-pcl
TIP
There are a number of different SQLite packages available – be sure to choose the correct one (it might not be the top result
in search).
Once you have the SQLite.NET library available, follow these three steps to use it to access a database:
1. Add a using statement – Add the following statement to the C# files where data access is required:
using SQLite;
2. Create a Blank Database – A database reference can be created by passing the file path the
SQLiteConnection class constructor. You do not need to check if the file already exists – it will automatically
be created if required, otherwise the existing database file will be opened. The dbPath variable should be
determined according the rules discussed earlier in this document:
3. Save Data – Once you have created a SQLiteConnection object, database commands are executed by
calling its methods, such as CreateTable and Insert like this:
db.CreateTable<Stock> ();
db.Insert (newStock); // after creating the newStock object
4. Retrieve Data – To retrieve an object (or a list of objects) use the following syntax:
The following code sample shows an entire database interaction using the SQLite.NET library to encapsulate the
underlying database access. It shows:
1. Creating the database file
2. Inserting some data by creating objects and then saving them
3. Querying the data
You'll need to include these namespaces:
The last one requires that you have added SQLite to your project. Note that the SQLite database table is defined by
adding attributes to a class (the Stock class) rather than a CREATE TABLE command.
[Table("Items")]
public class Stock {
[PrimaryKey, AutoIncrement, Column("_id")]
public int Id { get; set; }
[MaxLength(8)]
public string Symbol { get; set; }
}
public static void DoSomeDataAccess () {
Console.WriteLine ("Creating database, if it doesn't already exist");
string dbPath = Path.Combine (
Environment.GetFolderPath (Environment.SpecialFolder.Personal),
"ormdemo.db3");
var db = new SQLiteConnection (dbPath);
db.CreateTable<Stock> ();
if (db.Table<Stock> ().Count() == 0) {
// only insert the data if it doesn't already exist
var newStock = new Stock ();
newStock.Symbol = "AAPL";
db.Insert (newStock);
newStock = new Stock ();
newStock.Symbol = "GOOG";
db.Insert (newStock);
newStock = new Stock ();
newStock.Symbol = "MSFT";
db.Insert (newStock);
}
Console.WriteLine("Reading data");
var table = db.Table<Stock> ();
foreach (var s in table) {
Console.WriteLine (s.Id + " " + s.Symbol);
}
}
Using the [Table] attribute without specifying a table name parameter will cause the underlying database table to
have the same name as the class (in this case, "Stock"). The actual table name is important if you write SQL queries
directly against the database rather than use the ORM data access methods. Similarly the [Column("_id")]
attribute is optional, and if absent a column will be added to the table with the same name as the property in the
class.
SQLite Attributes
Common attributes that you can apply to your classes to control how they are stored in the underlying database
include:
[PrimaryKey] – This attribute can be applied to an integer property to force it to be the underlying table's
primary key. Composite primary keys are not supported.
[AutoIncrement] – This attribute will cause an integer property's value to be auto-increment for each new
object inserted into the database
[Column(name)] – Supplying the optional name parameter will override the default value of the
underlying database column's name (which is the same as the property).
[Table(name)] – Marks the class as being able to be stored in an underlying SQLite table. Specifying the
optional name parameter will override the default value of the underlying database table's name (which is
the same as the class name).
[MaxLength(value)] – Restrict the length of a text property, when a database insert is attempted.
Consuming code should validate this prior to inserting the object as this attribute is only 'checked' when a
database insert or update operation is attempted.
[Ignore] – Causes SQLite.NET to ignore this property. This is particularly useful for properties that have a
type that cannot be stored in the database, or properties that model collections that cannot be resolved
automatically be SQLite.
[Unique] – Ensures that the values in the underlying database column are unique.
Most of these attributes are optional, SQLite will use default values for table and column names. You should always
specify an integer primary key so that selection and deletion queries can be performed efficiently on your data.
NOTE
When writing SQL statements directly you create a dependency on the names of tables and columns in your database, which
have been generated from your classes and their attributes. If you change those names in your code you must remember to
update any manually written SQL statements.
Deleting an object
The primary key is used to delete the row, as shown here:
You can check the rowcount to confirm how many rows were affected (deleted in this case).
To change the threading mode, call SqliteConnection.SetConfig . For example, this line of code configures SQLite
for Serialized mode:
SqliteConnection.SetConfig(SQLiteConfig.Serialized);
The Android version of SQLite has a limitation that requires a few more steps. If the call to
SqliteConnection.SetConfig produces a SQLite exception such as library used incorrectly , then you must use the
following workaround:
1. Link to the native libsqlite.so library so that the sqlite3_shutdown and sqlite3_initialize APIs are made
available to the app:
[DllImport("libsqlite.so")]
internal static extern int sqlite3_shutdown();
[DllImport("libsqlite.so")]
internal static extern int sqlite3_initialize();
2. At the very beginning of the OnCreate method, add this code to shutdown SQLite, configure it for
Serialized mode, and reinitialize SQLite:
sqlite3_shutdown();
SqliteConnection.SetConfig(SQLiteConfig.Serialized);
sqlite3_initialize();
This workaround also works for the Mono.Data.Sqlite library. For more information about SQLite and multi-
threading, see SQLite and Multiple Threads.
Related Links
DataAccess Basic (sample)
DataAccess Advanced (sample)
Xamarin.Forms data access
Using ADO.NET with Android
7/25/2018 • 5 minutes to read • Edit Online
Xamarin has built-in support for the SQLite database that is available on Android and can be exposed using
familiar ADO.NET-like syntax. Using these APIs requires you to write SQL statements that are processed by
SQLite, such as CREATE TABLE , INSERT and SELECT statements.
Assembly References
To use access SQLite via ADO.NET you must add System.Data and Mono.Data.Sqlite references to your Android
project, as shown here:
Visual Studio
Visual Studio for Mac
Right-click References > Edit References... then click to select the required assemblies.
About Mono.Data.Sqlite
We will use the Mono.Data.Sqlite.SqliteConnection class to create a blank database file and then to instantiate
SqliteCommand objects that we can use to execute SQL instructions against the database.
Creating a Blank Database – Call the CreateFile method with a valid (ie. writeable) file path. You should check
whether the file already exists before calling this method, otherwise a new (blank) database will be created over the
top of the old one, and the data in the old file will be lost. Mono.Data.Sqlite.SqliteConnection.CreateFile (dbPath);
The dbPath variable should be determined according the rules discussed earlier in this document.
Creating a Database Connection – After the SQLite database file has been created you can create a connection
object to access the data. The connection is constructed with a connection string which takes the form of
Data Source=file_path , as shown here:
As mentioned earlier, a connection should never be re-used across different threads. If in doubt, create the
connection as required and close it when you're done; but be mindful of doing this more often than required too.
Creating and Executing a Database Command – Once we have a connection we can execute arbitrary SQL
commands against it. The code below shows a CREATE TABLE statement being executed.
using (var command = connection.CreateCommand ()) {
command.CommandText = "CREATE TABLE [Items] ([_id] int, [Symbol] ntext, [Name] ntext);";
var rowcount = command.ExecuteNonQuery ();
}
When executing SQL directly against the database you should take the normal precautions not to make invalid
requests, such as attempting to create a table that already exists. Keep track of the structure of your database so
that you don't cause a SqliteException such as SQLite error table [Items] already exists.
The code below illustrates how to perform simple SQLite operations and shows the results in as text in the
application's main window.
You'll need to include these namespaces:
using System;
using System.IO;
using Mono.Data.Sqlite;
if (!exists) {
Console.WriteLine("Creating database");
// Need to create the database before seeding it with some data
Mono.Data.Sqlite.SqliteConnection.CreateFile (dbPath);
connection = new SqliteConnection ("Data Source=" + dbPath);
EXECUTEREADER
The following method shows a WHERE clause in the SELECT statement. Because the code is crafting a complete
SQL statement it must take care to escape reserved characters such as the quote (') around strings.
return output;
}
The ExecuteReader method returns a SqliteDataReader object. In addition to the Read method shown in the
example, other useful properties include:
RowsAffected – Count of the rows affected by the query.
HasRows – Whether any rows were returned.
EXECUTESCALAR
Use this for SELECT statements that return a single value (such as an aggregate).
The ExecuteScalar method's return type is object – you should cast the result depending on the database query.
The result could be an integer from a COUNT query or a string from a single column SELECT query. Note that this is
different to other Execute methods that return a reader object or a count of the number of rows affected.
Related Links
DataAccess Basic (sample)
DataAccess Advanced (sample)
Android Data Recipes
Xamarin.Forms data access
Using Data in an App
7/25/2018 • 3 minutes to read • Edit Online
The DataAccess_Adv sample shows a working application that allows user-input and CRUD (Create, Read,
Update and Delete) database functionality. The application consists of two screens: a list and a data entry form. All
the data access code is re-usable in iOS and Android without modification.
After adding some data the application screens look like this on Android:
The Android Project is shown below – the code shown in this section is contained within the Orm directory:
The native UI code for the Activities in Android is out of scope for this document. Refer to the Android ListViews
and Adapters guide for more information on the UI controls.
Read
There are a couple of read operations in the sample:
Reading the list
Reading individual records
The two methods in the StockDatabase class are:
Real world applications will usually require some validation (such as required fields, minimum lengths or other
business rules). Good cross-platform applications implement as much of the validation logical as possible in shared
code, passing validation errors back up to the UI for display according to the platform's capabilities.
Delete
Unlike the Insert and Update methods, the Delete<T> method can accept just the primary key value rather than
a complete Stock object. In this example a Stock object is passed into the method but only the Id property is
passed on to the Delete<T> method.
Related Links
DataAccess Basic (sample)
DataAccess Advanced (sample)
Android Data Recipes
Xamarin.Forms data access
Google Messaging
4/13/2018 • 2 minutes to read • Edit Online
This section contains guides that describe how to implement Xamarin.Android apps using Google messaging
services.
NOTE
GCM has been superceded by Firebase Cloud Messaging (FCM). GCM server and client APIs have been deprecated and will
no longer be available as soon as April 11th, 2019.
Firebase Cloud Messaging (FCM ) is a service that facilitates messaging between mobile apps and server
applications. This article provides an overview of how FCM works, and it explains how to configure Google
Services so that your app can use FCM.
This topic provides a high-level overview of how Firebase Cloud Messaging routes messages between your
Xamarin.Android app and an app server, and it provides a step-by-step procedure for acquiring credentials so
that your app can use FCM services.
Overview
Firebase Cloud Messaging (FCM ) is a cross-platform service that handles the sending, routing, and queueing of
messages between server applications and mobile client apps. FCM is the successor to Google Cloud Messaging
(GCM ), and it is built on Google Play Services.
As illustrated in the following diagram, FCM acts as an intermediary between message senders and clients. A
client app is an FCM -enabled app that runs on a device. The app server (provided by you or your company) is the
FCM -enabled server that your client app communicates with through FCM. Unlike GCM, FCM makes it possible
for you to send messages to client apps directly via the Firebase Console Notifications GUI:
Using FCM, app servers can send messages to a single device, to a group of devices, or to a number of devices
that are subscribed to a topic. A client app can use FCM to subscribe to downstream messages from an app
server (for example, to receive remote notifications). For more information about the different types of Firebase
messages, see About FCM Messages.
1. The client app contacts FCM to obtain a registration token, passing the sender ID, API Key, and App ID to
FCM.
2. FCM returns a registration token to the client app.
3. The client app (optionally) forwards the registration token to the app server.
The app server caches the registration token for subsequent communications with the client app. The app server
can send an acknowledgement back to the client app to indicate that the registration token was received. After
this handshake takes place, the client app can receive messages from (or send messages to) the app server. The
client app may receive a new registration token if the old token is compromised (see Remote Notifications with
FCM for an example of how an app receives registration token updates).
When the client app no longer wants to receive messages from the app server, it can send a request to the app
server to delete the registration token. If the client app is uninstalled from a device, FCM detects this and
automatically notifies the app server to delete the registration token.
Downstream Messaging
The following diagram illustrates how Firebase Cloud Messaging stores and forwards downstream messages:
When the app server sends a downstream message to the client app, it uses the following steps as enumerated in
the above diagram:
1. The app server sends the message to FCM.
2. If the client device is not available, the FCM server stores the message in a queue for later transmission.
Messages are retained in FCM storage for a maximum of 4 weeks (for more information, see Setting the
lifespan of a message).
3. When the client device is available, FCM forwards the message to the client app on that device.
4. The client app receives the message from FCM, processes it, and displays it to the user. For example, if the
message is a remote notification, it is presented to the user in the notification area.
In this messaging scenario (where the app server sends a message to a single client app), messages can be up to
4kB in length.
For detailed information about receiving downstream FCM messages on Android, see Remote Notifications with
FCM.
Topic Messaging
Topic Messaging makes it possible for an app server to send a message to multiple devices that have opted in to
a particular topic. You can also compose and send topic messages via the Firebase Console Notifications GUI.
FCM handles the routing and delivery of topic messages to subscribed clients. This feature can be used for
messages such as weather alerts, stock quotes, and headline news.
The following steps are used in topic messaging (after the client app obtains a registration token as explained
earlier):
1. The client app subscribes to a topic by sending a subscribe message to FCM.
2. The app server sends topic messages to FCM for distribution.
3. FCM forwards topic messages to clients that have subscribed to that topic.
For more information about Firebase topic messaging, see Google's Topic Messaging on Android.
4. In the next screen, enter the package name of your app. In this example, the package name is
com.xamarin.fcmexample. This value must match the package name of your Android app. An app
nickname can also be entered in the App nickname field:
5. If your app uses Dynamic links, Invites, or Google Auth, you must also enter your debug signing
certificate. For more information about locating your signing certificate, see Finding your Keystore's MD5
or SHA1 Signature. In this example, the signing certificate is left blank.
6. Click ADD APP:
A Server API key and a Client ID are automatically generated for the app. This information is packaged in
a google-services.json file that is automatically downloaded when you click ADD APP. Be sure to save
this file in a safe place.
For a detailed example of how to add google-services.json to an app project to receive FCM push notification
messages on Android, see Remote Notifications with FCM.
Summary
This article provided an overview of Firebase Cloud Messaging (FCM ). It explained the various credentials that
are used to identify and authorize messaging between app servers and client apps. It illustrated the registration
and downstream messaging scenarios, and it detailed the steps for registering your app with FCM to use FCM
services.
Related Links
Firebase Cloud Messaging
Remote Notifications with Firebase Cloud Messaging
4/13/2018 • 21 minutes to read • Edit Online
This walkthrough provides a step -by-step explanation of how to use Firebase Cloud Messaging to implement
remote notifications (also called push notifications) in a Xamarin.Android application. It illustrates how to
implement the various classes that are needed for communications with Firebase Cloud Messaging (FCM ),
provides examples of how to configure the Android Manifest for access to FCM, and demonstrates downstream
messaging using the Firebase Console.
Requirements
Before you can proceed with this walkthrough, you must acquire the necessary credentials to use Google's FCM
servers; this process is explained in Firebase Cloud Messaging. In particular, you must download the google-
services.json file to use with the example code presented in this walkthrough. If you have not yet created a
project in the Firebase Console (or if you have not yet downloaded the google-services.json file), see Firebase
Cloud Messaging.
To run the example app, you will need an Android test device or emulator that is compatibile with Firebase.
Firebase Cloud Messaging supports clients running on Android 2.3 (Gingerbread) or higher, and these devices
must also have the the Google Play Store app installed (Google Play Services 9.2.1 or later is required). If you do
not yet have the Google Play Store app installed on your device, visit the Google Play web site to download and
install it. Alternately, you can use the Android SDK emulator running Android 2.3 or later instead of a test device
(you do not have to install the Google Play Store if you are using the Android SDK emulator).
If you get an error during installation of the NuGet, close the FCMClient project, open it again, and retry the
NuGet installation.
When you install Xamarin.GooglePlayServices.Base, all of the necessary dependencies are also installed. Edit
MainActivity.cs and add the following using statement:
using Android.Gms.Common;
using Firebase.Messaging;
using Firebase.Iid;
using Android.Util;
The first two statements make types in the Xamarin.Firebase.Messaging NuGet package available to
FCMClient code. Android.Util adds logging functionality that will be used to observe transactions with FMS.
Add the Google Services JSON File
The next step is to add the google-services.json file to the root directory of your project:
Visual Studio
Visual Studio for Mac
1. Copy google-services.json to the project folder.
2. Add google-services.json to the app project (click Show All Files in the Solution Explorer, right click
google-services.json, then select Include in Project).
3. Select google-services.json in the Solution Explorer window.
4. In the Properties pane, set the Build Action to GoogleServicesJson (if the GoogleServicesJson build
action is not shown, save and close the Solution, then reopen it):
When google-services.json is added to the project (and the GoogleServicesJson build action is set), the build
process extracts the client ID and API key and then adds these credentials to the merged/generated
AndroidManifest.xml that resides at obj/Debug/android/AndroidManifest.xml. This merge process
automatically adds any permissions and other FCM elements that are needed for connection to FCM servers.
This TextView will be used to display messages that indicate whether Google Play Services is installed. Save the
changes to Main.axml. Edit MainActivity.cs and add the following instance variable declaration to the
MainActivity class:
TextView msgText;
Google recommends that Android apps check for the presence of the Google Play Services APK before accessing
Google Play Services features (for more information, see Check for Google Play services). In the following
example, the OnCreate method will verify that Google Play Services is available before the app attempts to use
FCM services. Add the following method to the MainActivity class:
This code checks the device to see if the Google Play Services APK is installed. If it is not installed, a message is
displayed in the TextBox that instructs the user to download an APK from the Google Play Store (or to enable it
in the device's system settings).
Replace the OnCreate method with the following code:
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
SetContentView (Resource.Layout.Main);
msgText = FindViewById<TextView> (Resource.Id.msgText);
IsPlayServicesAvailable ();
}
IsPlayServicesAvailable is called at the end of OnCreate so that the Google Play Services check runs each time
the app starts. If your app has an OnResume method, it should call IsPlayServicesAvailable from OnResume as
well. Completely rebuild and run the app. If all is configured properly, you should see a screen that looks like the
following screenshot:
If you don't get this result, verify that the Google Play Services APK is installed on your device (for more
information, see Setting Up Google Play Services). Also verify that you have added the
Xamarin.Google.Play.Services.Base package to your FCMClient project as explained earlier.
using System;
using Android.App;
using Firebase.Iid;
using Android.Util;
namespace FCMClient
{
[Service]
[IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
public class MyFirebaseIIDService : FirebaseInstanceIdService
{
const string TAG = "MyFirebaseIIDService";
public override void OnTokenRefresh()
{
var refreshedToken = FirebaseInstanceId.Instance.Token;
Log.Debug(TAG, "Refreshed token: " + refreshedToken);
SendRegistrationToServer(refreshedToken);
}
void SendRegistrationToServer(string token)
{
// Add custom implementation, as needed.
}
}
}
This service implements an OnTokenRefresh method that is invoked when the registration token is initially created
or changed. When OnTokenRefresh runs, it retrieves the latest token from the FirebaseInstanceId.Instance.Token
property (which is updated asynchronously by FCM ). In this example, the refreshed token is logged so that it can
be viewed in the output window:
OnTokenRefresh is invoked infrequently: it is used to update the token under the following circumstances:
When the app is installed or uninstalled.
When the user deletes app data.
When the app erases the Instance ID.
When the security of the token has been compromised.
According to Google's Instance ID documentation, the FCM Instance ID service will request that the app refresh
its token periodically (typically, every 6 months).
OnTokenRefresh also calls SendRegistrationToAppServer to associate the user's registration token with the server-
side account if any) that is maintained by the application:
(
Because this implementation depends on the design of the app server, an empty method body is provided in this
example. If your app server requires FCM registration information, modify SendRegistrationToAppServer to
associate the user's FCM instance ID token with any server-side account maintained by your app. (Note that the
token is opaque to the client app.)
When a token is sent to the app server, SendRegistrationToAppServer should maintain a boolean to indicate
whether the token has been sent to the server. If this boolean is false, SendRegistrationToAppServer sends the
token to the app server – otherwise, the token was already sent to the app server in a previous call. In some cases
(such as this FCMClient example), the app server does not need the token; therefore, this method is not required
for this example.
<Button
android:id="@+id/logTokenButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Log Token" />
Edit MainActivity.cs and add the following member declaration to the MainActivity class:
This code logs the current token to the output window when the Log Token button is tapped.
Handle Notification Intents
When the user taps a notification issued from FCMClient, any data accompanying that notification message is
made available in Intent extras. Edit MainActivity.cs and add the following code to the top of the OnCreate
method (before the call to IsPlayServicesAvailable ):
if (Intent.Extras != null)
{
foreach (var key in Intent.Extras.KeySet())
{
var value = Intent.Extras.GetString(key);
Log.Debug(TAG, "Key: {0} Value: {1}", key, value);
}
}
The app's launcher Intent is fired when the user taps its notification message, so this code will log any
accompanying data in the Intent to the output window. If a different Intent must be fired, the click_action
field of the notification message must be set to that Intent (the launcher Intent is used when no click_action
is specified).
Background Notifications
Build and run the FCMClient app. The Log Token button is displayed:
Tap the Log Token button. A message like the following should be displayed in the IDE output window:
The long string labeled with token is the instance ID token that you will paste into the Firebase Console – select
and copy this string to the clipboard. If you do not see an instance ID token, add the following line to the top of
the OnCreate method to verify that google-services.json was parsed correctly:
The google_app_id value logged to the output window should match the mobilesdk_app_id value recorded in
google-services.json.
Send a Message
Sign into the Firebase Console, select your project, click Notifications, and click SEND YOUR FIRST
MESSAGE:
On the Compose message page, enter the message text and select Single device. Copy the instance ID token
from the IDE output window and paste it into the FCM registration token field of the Firebase Console:
On the Android device (or emulator), background the app by tapping the Android Overview button and touching
the home screen. When the device is ready, click SEND MESSAGE in the Firebase Console:
When the Review message dialog is displayed, click SEND. The notification icon should appear in the
notification area of the device (or emulator):
Open the notification icon to view the message. The notification message should be exactly what was typed into
the Message text field of the Firebase Console:
Tap the notification icon to return to the FCMClient app. The Intent extras sent to FCMClient are listed in the
IDE output window:
In this example, the from key is set to the Firebase project number of the app (in this example, 41590732 ), and the
collapse_key is set to its package name (com.xamarin.fcmexample). If you do not receive a message, try
deleting the FCMClient app on the device (or emulator) and repeat the above steps.
NOTE
If you force-close the app, FCM will stop delivering notifications. Android prevents background service broadcasts from
inadvertently or unnecessarily launching components of stopped applications. (For more information about this behavior,
see Launch controls on stopped applications.) For this reason, it is necessary to manually uninstall the app each time you
run it and stop it from a debug session – this forces FCM to generate a new token so that messages will continue to be
received.
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_stat_ic_notification" />
<Button
android:id="@+id/subscribeButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:text="Subscribe to Notifications" />
This XML adds a Subscribe to Notification button to the layout. Edit MainActivity.cs and add the following
code to the end of the OnCreate method:
If the app has subscribed successfully, you should see topic sync succeeded in the IDE output window:
When this message is seen in the output window, the notification icon should also appear in the notification area
on the Android device. Open the notification icon to view the topic message:
If you do not receive a message, try deleting the FCMClient app on the device (or emulator) and repeat the
above steps.
Foreground Notifications
To receive notifications in foregrounded apps, you must implement FirebaseMessagingService . This service is also
required for receiving data payloads and for sending upstream messages. The following examples illustrate how
to implement a service that extends FirebaseMessagingService – the resulting app will be able to handle remote
notifications while it is running in the foreground.
Implement FirebaseMessagingService
The FirebaseMessagingService service includes an OnMessageReceived method that you write to handle incoming
messages. Note that OnMessageReceived is invoked for notification messages only when the app is running in the
foreground. When the app is running in the background, an automatically generated notification is displayed (as
demonstrated earlier in this walkthrough).
Add a new file called MyFirebaseMessagingService.cs and replace its template code with the following:
using System;
using Android.App;
using Android.Content;
using Android.Media;
using Android.Util;
using Firebase.Messaging;
namespace FCMClient
{
[Service]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
public class MyFirebaseMessagingService : FirebaseMessagingService
{
const string TAG = "MyFirebaseMsgService";
public override void OnMessageReceived(RemoteMessage message)
{
Log.Debug(TAG, "From: " + message.From);
Log.Debug(TAG, "Notification Message Body: " + message.GetNotification().Body);
}
}
}
Note that the MESSAGING_EVENT intent filter must be declared so that new FCM messages are directed to
MyFirebaseMessagingService :
When the client app receives a message from FCM, OnMessageReceived extracts the message content from the
passed-in RemoteMessage object by calling its GetNotification method. Next, it logs the message content so that
it can be viewed in the IDE output window:
NOTE
If you set breakpoints in FirebaseMessagingService , your debugging session may or may not hit these breakpoints
because of how FCM delivers messages.
using FCMClient;
using System.Collections.Generic;
To distinguish this notification from background notifications, this code marks notifications with an icon that
differs from the applicatiion icon. Add ic_stat_ic_notification.png to Resources/drawable and include it in the
FCMClient project.
The SendNotification method uses Notification.Builder to create the notification, and NotificationManager is
used to launch the notification. The notification holds a PendingIntent that will allow the user to open the app and
view the contents of the string passed into messageBody . Depending on the versions of Android that you intend to
target with your app, you may want to use NotificationCompat.Builder instead. For more information about
Notification.Builder , see Local Notifications.
SendNotification(message.GetNotification().Body, message.Data);
As a result of these changes, SendNotification will run whenever a notification is received while the app is in the
foreground, and the notification will appear in the notification area. If the app is backgrounded, SendNotification
will not run and, instead, a background notification (illustrated earlier in this walkthrough) will be launched.
Send the Last Message
Uninstall the app, rebuild it, run it again, then use the following steps to send the last message:
1. In the Firebase Console, click NEW MESSAGE.
2. On the Compose message page, enter the message text and select Single device.
3. Copy the token string from the IDE output window and paste it into the FCM registration token field of
the Firebase Console as before.
4. Ensure that the app is running in the foreground, then click SEND MESSAGE in the Firebase Console:
This time, the message that was logged in the output window is also packaged in a new notification – the
notification icon appears in the notification tray while the app is running in the foreground:
When you open the notification, you should see the last message that was sent from the Firebase Console
Notifications GUI:
Disconnecting from FCM
To unsubscribe from a topic, call the UnsubscribeFromTopic method on the FirebaseMessaging class. For
example, to unsubscribe from the news topic subscribed to earlier, an Unsubscribe button could be added to the
layout with the following handler code:
To unregister the device from FCM altogether, delete the instance ID by calling the DeleteInstanceId method on
the FirebaseInstanceId class. For example:
FirebaseInstanceId.Instance.DeleteInstanceId();
This method call deletes the the instance ID and the data associated with it. As a result, the periodic sending of
FCM data to the device is halted.
Troubleshooting
The following describe issues and workarounds that may arise when using Firebase Cloud Messaging with
Xamarin.Android.
FirebaseApp is not Initialized
In some cases, you may see this error message:
This is a known problem that you can work around by cleaning the solution and rebuilding the project (Build >
Clean Solution, Build > Rebuild Solution). For more information, see this forum discussion.
Summary
This walkthrough detailed the steps for implementing Firebase Cloud Messaging remote notifications in a
Xamarin.Android application. It described how to install the required packages needed for FCM communications,
and it explained how to configure the Android Manifest for access to FCM servers. It provided example code that
illustrates how to check for the presence of Google Play Services. It demonstrated how to implement an instance
ID listener service that negotiates with FCM for a registration token, and it explained how this code creates
background notifications while the app is backgrounded. It explained how to subscribe to topic messages, and it
provided an example implementation of a message listener service that is used to receive and display remote
notifications while the app is running in the foreground.
Related Links
FCMNotifications (sample)
Firebase Cloud Messaging
Google Cloud Messaging
4/13/2018 • 8 minutes to read • Edit Online
Google Cloud Messaging (GCM ) is a service that facilitates messaging between mobile apps and server
applications. This article provides an overview of how GCM works, and it explains how to configure Google
Services so your app can use GCM.
This topic provides a high-level overview of how Google Cloud Messaging routes messages between your app
and an app server, and it provides a step-by-step procedure for acquiring credentials so that your app can use
GCM services.
NOTE
GCM has been superceded by Firebase Cloud Messaging (FCM). GCM server and client APIs have been deprecated and will
no longer be available as soon as April 11th, 2019.
Overview
Google Cloud Messaging (GCM ) is a service that handles the sending, routing, and queueing of messages
between server applications and mobile client apps. A client app is a GCM -enabled app that runs on a device. The
app server (provided by you or your company) is the GCM -enabled server that your client app communicates with
through GCM:
Using GCM, app servers can send messages to a single device, a group of devices, or a number of devices that are
subscribed to a topic. Your client app can use GCM to subscribe to downstream messages from an app server (for
example, to receive remote notifications). Also, GCM makes it possible for client apps to send upstream messages
back to the app server.
For information about implementing an app server for GCM, see About GCM Connection Server.
1. The client app contacts GCM to obtain a registration token, passing the sender ID to GCM.
2. GCM returns a registration token to the client app.
3. The client app forwards the registration token to the app server.
The app server caches the registration token for subsequent communications with the client app. Optionally, the
app server can send an acknowledgement back to the client app to indicate that the registration token was
received. After this handshake takes place, the client app can receive messages from (or send messages to) the app
server.
When the client app no longer wants to receive messages from the app server, it can send a request to the app
server to delete the registration token. If the client app is receiving topic messages (explained later in this article), it
can unsubscribe from the topic. If the client app is uninstalled from a device, GCM detects this and automatically
notifies the app server to delete the registration token.
Google's Registering Client Apps explains the registration process in more detail; it explains unregistration and
unsubscription, and it describes the process of unregistration when a client app is uninstalled.
Downstream Messaging
When the app server sends a downstream message to the client app, it follows the steps illustrated in the
following diagram:
1. The client app sends a message to the GCM XMPP connection server.
2. If the app server is disconnected, the GCM server stores the message in a queue for later forwarding.
3. When the app server is re-connected, GCM forwards the message to the app server.
4. The app server parses the message to verify the identity of the client app, then it sends an "ack" to GCM to
acknowledge message receipt.
5. The app server processes the message.
Google's Upstream Messages explains how to structure JSON -encoded messages and send them to app servers
that run Google's XMPP -based Cloud Connection Server.
Note that this package name is also the application ID for your app.
3. The Choose and configure services section lists the Google services that you can add to your app. Click
Cloud Messaging:
4. Next, click ENABLE GOOGLE CLOUD MESSAGING:
5. A Server API key and a Sender ID are generated for your app. Record these values and click CLOSE:
Protect the API key – it is not intended for public use. If the API key is compromised, unauthorized servers
could publish messages to client applications. Best practices for securely using API keys provides useful
guidelines for protecting your API Key.
View Your Project Settings
You can view your project settings at any time by signing into the Google Cloud Console and selecting your
project. For example, you can view the Sender ID by selecting your project in the pull down menu at the top of
the page (in this example, the project is called XamarinGCM ). The Sender ID is the Project number as shown in
this screenshot (the Sender ID here is 9349932736):
To view the API key, click API Manager and then click Credentials:
For Further Reading
Google's Registering Client Apps describes the client registration process in more detail, and it provides
information about configuring automatic retry and keeping the registration state in sync.
RFC 6120 and RFC 6121 explain and define the Extensible Messaging and Presence Protocol (XMPP ).
Summary
This article provided an overview of Google Cloud Messaging (GCM ). It explained the various credentials that are
used to identify and authorize messaging between app servers and client apps. It illustrated the most common
messaging scenarios, and it detailed the steps for registering your app with GCM to use GCM services.
Related Links
Cloud Messaging
Remote Notifications With Google Cloud Messaging
4/13/2018 • 20 minutes to read • Edit Online
This walkthrough provides a step -by-step explanation of how to use Google Cloud Messaging to implement
remote notifications (also called push notifications) in a Xamarin.Android application. It describes the various
classes that you must implement to communicate with Google Cloud Messaging (GCM ), it explains how to set
permissions in the Android Manifest for access to GCM, and it demonstrates end -to -end messaging with a sample
test program.
NOTE
GCM has been superceded by Firebase Cloud Messaging (FCM). GCM server and client APIs have been deprecated and will
no longer be available as soon as April 11th, 2019.
Walkthrough
To begin, let's create a new empty Solution called RemoteNotifications. Next, let's add a new Android project to
this Solution that is based on the Android App template. Let's call this project ClientApp. (If you're not familiar
with creating Xamarin.Android projects, see Hello, Android.) The ClientApp project will contain the code for the
Xamarin.Android client application that receives remote notifications via GCM.
Add Required Packages
Before we can implement our client app code, we must install several packages that we'll use for communication
with GCM. Also, we must add the Google Play Store application to our device if it is not already installed.
Add the Xamarin Google Play Services GCM Package
To receive messages from Google Cloud Messaging, the Google Play Services framework must be present on the
device. Without this framework, an Android application cannot receive messages from GCM servers. Google Play
Services runs in the background while the Android device is powered on, quietly listening for messages from
GCM. When these messages arrive, Google Play Services converts the messages into intents and then broadcasts
these intents to applications that have registered for them.
In Visual Studio, right-click References > Manage NuGet Packages ...; in Visual Studio for Mac, right-click
Packages > Add Packages.... Search for Xamarin Google Play Services - GCM and install this package into
the ClientApp project:
When you install Xamarin Google Play Services - GCM, Xamarin Google Play Services - Base is
automatically installed. If you get an error, change the project's Minimum Android to target setting to a value other
than Compile using SDK version and try the NuGet install again.
Next, edit MainActivity.cs and add the following using statements:
using Android.Gms.Common;
using Android.Util;
This makes types in the Google Play Services GMS package available to our code, and it adds logging
functionality that we will use to track our transactions with GMS.
Google Play Store
To receive messages from GCM, the Google Play Store application must be installed on the device. (Whenever a
Google Play application is installed on a device, Google Play Store is also installed, so it's likely that it is already
installed on your test device.) Without Google Play, an Android application cannot receive messages from GCM. If
you do not yet have the Google Play Store app installed on your device, visit the Google Play web site to download
and install Google Play.
Alternately, you can use an Android emulator running Android 2.2 or later instead of a test device (you do not
have to install Google Play Store on an Android emulator). However, if you use an emulator, you must use Wi-Fi to
connect to GCM and you must open several ports in your Wi-Fi firewall as explained later in this walkthrough.
Set the Package Name
In Google Cloud Messaging, we specified a package name for our GCM -enabled app (this package name also
serves as the application ID that is associated with our API key and Sender ID ). Let's open the properties for the
ClientApp project and set the package name to this string. In this example, we set the package name to
com.xamarin.gcmexample :
Note that the client app will be unable to receive a registration token from GCM if this package name does not
exactly match the package name that we entered into the Google Developer console.
Add Permissions to the Android Manifest
An Android application must have the following permissions configured before it can receive notifications from
Google Cloud Messaging:
com.google.android.c2dm.permission.RECEIVE– Grants permission to our app to register and receive
messages from Google Cloud Messaging. (What does c2dm mean? This stands for Cloud to Device
Messaging, which is the now -deprecated predecessor to GCM. GCM still uses c2dm in many of its
permission strings.)
android.permission.WAKE_LOCK – (Optional) Prevents the device CPU from from going to sleep while
listening for a message.
android.permission.INTERNET – Grants internet access so the client app can communicate with GCM.
package_name .permission.C2D_MESSAGE – Registers the application with Android and requests permission
to exclusively receive all C2D (cloud to device) messages. The package_name prefix is the same as your
application ID.
We'll set these permissions in the Android manifest. Let's edit AndroidManifest.xml and replace the contents
with the following XML:
In the above XML, change YOUR_PACKAGE_NAME to the package name for your client app project. For example,
com.xamarin.gcmexample .
Check for Google Play Services
For this walkthrough, we're creating a bare-bones app with a single TextView in the UI. This app doesn't directly
indicate interaction with GCM. Instead, we'll watch the output window to see how our app handshakes with GCM,
and we'll check the notification tray for new notifications as they arrive.
First, let's create a layout for the message area. Edit Resources.layout.Main.axml and replace the contents with
the following XML:
TextView msgText;
This code checks the device to see if the Google Play Services APK is installed. If it is not installed, a message is
displayed in the message area that instructs the user to download an APK from the Google Play Store (or enable it
in the device's system settings). Because we want to run this check when the client app starts, we'll add a call to this
method at the end of OnCreate .
Next, replace the OnCreate method with the following code:
SetContentView (Resource.Layout.Main);
msgText = FindViewById<TextView> (Resource.Id.msgText);
IsPlayServicesAvailable ();
}
This code checks for the presence of the Google Play Services APK and writes the result to the message area.
Let's completely rebuild and run the app. You should see a screen that looks like the following screenshot:
If you don't get this result, verify that the Google Play Services APK is installed on your device and that the
Xamarin Google Play Services - GCM package is added to your ClientApp project as explained earlier. If you
get a build error, try cleaning the Solution and building the project again.
Next, we'll write code to contact GCM and get back a registration token.
Register with GCM
Before the app can receive remote notifications from the app server, it must register with GCM and get back a
registration token. The work of registering our application with GCM is handled by an IntentService that we
create. Our IntentService performs the following steps:
1. Uses the InstanceID API to generate security tokens that authorize our client app to access the app server.
In return, we get back a registration token from GCM.
2. Forwards the registration token to the app server (if the app server requires it).
3. Subscribes to one or more notification topic channels.
After we implement this IntentService , we'll test it to see if we get back a registration token from GCM.
Add a new file called RegistrationIntentService.cs and replace the template code with the following:
using System;
using Android.App;
using Android.Content;
using Android.Util;
using Android.Gms.Gcm;
using Android.Gms.Gcm.Iid;
namespace ClientApp
{
[Service(Exported = false)]
class RegistrationIntentService : IntentService
{
static object locker = new object();
In the above sample code, change YOUR_SENDER_ID to the Sender ID number for your client app project. To get
the Sender ID for your project:
1. Log into the Google Cloud Console and select your project name from the pull down menu. In the Project
info pane that is displayed for your project, click Go to project settings:
2. On the Settings page, locate the Project number – this is the Sender ID for your project:
We want to start our RegistrationIntentService when our app starts running. Edit MainActivity.cs and modify
the OnCreate method so that our RegistrationIntentService is started after we check for the presence of Google
Play Services:
SetContentView(Resource.Layout.Main);
msgText = FindViewById<TextView> (Resource.Id.msgText);
if (IsPlayServicesAvailable ())
{
var intent = new Intent (this, typeof (RegistrationIntentService));
StartService (intent);
}
}
Now let's take a look at each section of RegistrationIntentService to understand how it works.
First, we annotate our RegistrationIntentService with the following attribute to indicate that our service is not to
be instantiated by the system:
OnHandleIntent first calls Google's InstanceID.GetToken method to request a registration token from GCM. We
wrap this code in a lock to guard against the possibility of multiple registration intents occurring simultaneously
– the lock ensures that these intents are processed sequentially. If we fail to get a registration token, an exception
is thrown and we log an error. If the registration succeeds, token is set to the registration token we got back from
GCM:
F o r w a r d t h e R e g i st r a t i o n To k e n t o t h e A p p Se r v e r
If we get a registration token (that is, no exception was thrown), we call SendRegistrationToAppServer to associate
the user's registration token with the server-side account (if any) that is maintained by our application. Because
this implementation depends on the design of the app server, an empty method is provided here:
In some cases, the app server does not need the user's registration token; in that case, this method can be omitted.
When a registration token is sent to the app server, SendRegistrationToAppServer should maintain a boolean to
indicate whether the token has been sent to the server. If this boolean is false, SendRegistrationToAppServer sends
the token to the app server – otherwise, the token was already sent to the app server in a previous call.
Su b sc r i b e t o t h e N o t i fi c a t i o n To p i c
Next, we call our Subscribe method to indicate to GCM that we want to subscribe to a notification topic. In
Subscribe , we call the GcmPubSub.Subscribe API to subscribe our client app to all messages under
/topics/global :
The app server must send notification messages to /topics/global if we are to receive them. Note that the topic
name under /topics can be anything you want, as long as the app server and the client app both agree on these
names. (Here, we chose the name global to indicate that we want to receive messages on all topics supported by
the app server.)
For information about GCM topic messaging on the server side, see Google's Send Messaging to Topics.
Implement an Instance ID Listener Service
Registration tokens are unique and secure; however, the client app (or GCM ) may need to refresh the registration
token in the event of app reinstallation or a security issue. For this reason, we must implement an
InstanceIdListenerService that responds to token refresh requests from GCM.
Add a new file called InstanceIdListenerService.cs and replace the template code with the following:
using Android.App;
using Android.Content;
using Android.Gms.Gcm.Iid;
namespace ClientApp
{
[Service(Exported = false), IntentFilter(new[] { "com.google.android.gms.iid.InstanceID" })]
class MyInstanceIDListenerService : InstanceIDListenerService
{
public override void OnTokenRefresh()
{
var intent = new Intent (this, typeof (RegistrationIntentService));
StartService (intent);
}
}
}
Annotate InstanceIdListenerService with the following attribute to indicate that the service is not to be
instantiated by the system and that it can receive GCM registration token (also called instance ID) refresh requests:
The OnTokenRefresh method in our service starts the RegistrationIntentService so that it can intercept the new
registration token.
Test Registration with GCM
Let's completely rebuild and run the app. If you successfully receive a registration token from GCM, the
registration token should be displayed in the output window. For example:
using Android.App;
using Android.Content;
using Android.OS;
using Android.Gms.Gcm;
using Android.Util;
namespace ClientApp
{
[Service (Exported = false), IntentFilter (new [] { "com.google.android.c2dm.intent.RECEIVE" })]
public class MyGcmListenerService : GcmListenerService
{
public override void OnMessageReceived (string from, Bundle data)
{
var message = data.GetString ("message");
Log.Debug ("MyGcmListenerService", "From: " + from);
Log.Debug ("MyGcmListenerService", "Message: " + message);
SendNotification (message);
}
Let's take a look at each section of our GcmListenerService to understand how it works.
First, we annotate GcmListenerService with an attribute to indicate that this service is not to be instantiated by the
system, and we include an intent filter to indicate that it receives GCM messages:
When GcmListenerService receives a message from GCM, the OnMessageReceived method is invoked. This method
extracts the message content from the passed-in Bundle , logs the message content (so we can view it in the
output window ), and calls SendNotification to launch a local notification with the received message content:
The SendNotification method uses Notification.Builder to create the notification, and then it uses the
NotificationManager to launch the notification. Effectively, this converts the remote notification message into a
local notification to be presented to the user. For more information about using Notification.Builder and
NotificationManager , see Local Notifications.
Declare the Receiver in the Manifest
Before we can receive messages from GCM, we must declare the GCM listener in the Android manifest. Let's edit
AndroidManifest.xml and replace the <application> section with the following XML:
In the above XML, change YOUR_PACKAGE_NAME to the package name for your client app project. In our
walkthrough example, the package name is com.xamarin.gcmexample .
Let's look at what each setting in this XML does:
SETTING DESCRIPTION
com.google.android.c2dm.permission.SEND Declares that only GCM servers can send messages directly to
the app.
com.google.android.c2dm.intent.REGISTRATION Intent filter advertising that our app handles new registration
intents (that is, we have implemented an Instance ID Listener
Service).
Alternatively, you can decorate GcmListenerService with these attributes rather than specifying them in XML; here
we specify them in AndroidManifest.xml so that the code samples are easier to follow.
Create a Message Sender to Test the App
Let's add a C# desktop console application project to the Solution and call it MessageSender. We'll use this
console application to simulate an application server – it will send notification messages to ClientApp via GCM.
Add the Json.NET Package
In this console app, we're building a JSON payload that contains the notification message we want to send to the
client app. We'll use the Json.NET package in MessageSender to make it easier to build the JSON object
required by GCM. In Visual Studio, right-click References > Manage NuGet Packages ...; in Visual Studio for
Mac, right-click Packages > Add Packages....
Let's search for the Json.NET package and install it in the project:
Add a Reference to System.Net.Http
We'll also need to add a reference to System.Net.Http so that we can instantiate an HttpClient for sending our
test message to GCM. In the MessageSender project, Right-click References > Add Reference and scroll down
until you see System.Net.Http. Put a check mark next to System.Net.Http and click OK.
Implement Code that Sends a Test Message
In MessageSender, edit Program.cs and replace the contents with the following code:
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
namespace MessageSender
{
class MessageSender
{
public const string API_KEY = "YOUR_API_KEY";
public const string MESSAGE = "Hello, Xamarin!";
client.DefaultRequestHeaders.TryAddWithoutValidation (
"Authorization", "key=" + API_KEY);
Task.WaitAll(client.PostAsync (url,
new StringContent(jGcmData.ToString(), Encoding.Default, "application/json"))
.ContinueWith(response =>
{
Console.WriteLine(response);
Console.WriteLine("Message sent: check the client device notification tray.");
}));
}
}
catch (Exception e)
{
Console.WriteLine("Unable to send GCM message:");
Console.Error.WriteLine(e.StackTrace);
}
}
}
}
In the above code, change YOUR_API_KEY to the API Key for your client app project.
This test app server sends the following JSON -formatted message to GCM:
{
"to": "/topics/global",
"data": {
"message": "Hello, Xamarin!"
}
}
GCM, in turn, forwards this message to your client app. Let's build MessageSender and open a console window
where we can run it from the command line.
Try It!
Now we're ready to test our client app. If you're using an emulator or if your device is communicating with GCM
over Wi-Fi, you must open the following TCP ports on your firewall for GCM messages to get through: 5228,
5229, and 5230.
Start your client app and watch the output window. After the RegistrationIntentService successfully receives a
registration token from GCM, the output window should display the token with log output resembling the
following:
At this point the client app is ready to receive a remote notification message. From the command line, run the
MessageSender.exe program to send a "Hello, Xamarin" notification message to the client app. If you have not
yet built the MessageSender project, do so now.
To run MessageSender.exe under Visual Studio, open a command prompt, change to the
MessageSender/bin/Debug directory, and run the command directly:
MessageSender.exe
To run MessageSender.exe under Visual Studio for Mac, open a Terminal session, change to
MessageSender/bin/Debug the directory, and use mono to run MessageSender.exe
mono MessageSender.exe
It may take up to a minute for the message to propagate through GCM and back down to your client app. If the
message is received successfully, we should see output resembling the following in the output window:
In addition, you should notice that a new notification icon has appeared in the notification tray:
When you open the notification tray to view notifications, you should see our remote notification:
Summary
This walkthrough detailed the steps for implementing remote notifications in a Xamarin.Android application. It
described how to install additional packages needed for GCM communications, and it explained how to configure
app permissions for access to GCM servers. It provided example code that illustrates how to check for the
presence of Google Play Services, how to implement a registration intent service and instance ID listener service
that negotiates with GCM for a registration token, and how to implement a GCM listener service that receives and
processes remote notification messages. Finally, we implemented a command-line test program to send test
notifications to our client app through GCM.
Related Links
GCM RemoteNotifications (sample)
Google Cloud Messaging
Introduction to Web Services
5/8/2018 • 15 minutes to read • Edit Online
This guide demonstrates how to consume different web service technologies. Topics covered include
communicating with REST services, SOAP services, and Windows Communication Foundation services.
To function correctly, many mobile applications are dependent on the cloud, and so integrating web services into
mobile applications is a common scenario. The Xamarin platform supports consuming different web service
technologies, and includes in-built and third-party support for consuming RESTful, ASMX, and Windows
Communication Foundation (WCF ) services.
This article discusses the following topics:
REST Services
ASP.Net Web Services (ASMX)
WCF Services
For customers using Xamarin.Forms, there are complete examples using each of these technologies in the
Xamarin.Forms Web Services documentation.
IMPORTANT
In iOS 9, App Transport Security (ATS) enforces secure connections between internet resources (such as the app's back-end
server) and the app, thereby preventing accidental disclosure of sensitive information. Since ATS is enabled by default in apps
built for iOS 9, all connections will be subject to ATS security requirements. If connections do not meet these requirements,
they will fail with an exception.
You can opt-out of ATS if it is not possible to use the HTTPS protocol and secure communication for internet
resources. This can be achieved by updating the app's Info.plist file. For more information see App Transport
Security.
REST
Representational State Transfer (REST) is an architectural style for building web services. REST requests are made
over HTTP using the same HTTP verbs that web browsers use to retrieve web pages and to send data to servers.
The verbs are:
GET – this operation is used to retrieve data from the web service.
POST – this operation is used to create a new item of data on the web service.
PUT – this operation is used to update an item of data on the web service.
PATCH – this operation is used to update an item of data on the web service by describing a set of instructions
about how the item should be modified. This verb is not used in the sample application.
DELETE – this operation is used to delete an item of data on the web service.
Web service APIs that adhere to REST are called RESTful APIs, and are defined using:
A base URI.
HTTP methods, such as GET, POST, PUT, PATCH, or DELETE.
A media type for the data, such as JavaScript Object Notation (JSON ).
The simplicity of REST has helped make it the primary method for accessing web services in mobile applications.
Consuming REST Services
There are a number of libraries and classes that can be used to consume REST services, and the following
subsections discuss them. For more information about consuming a REST service, see Consuming a RESTful Web
Service.
HttpClient
The Microsoft HTTP Client Libraries provides the HttpClient class, which is used to send and receive requests
over HTTP. It provides functionality for sending HTTP requests and receiving HTTP responses from a URI-
identified resource. Each request is sent as an asynchronous operation. For more information about asynchronous
operations, see Async Support Overview.
The HttpResponseMessage class represents an HTTP response message received from the web service after an
HTTP request has been made. It contains information about the response, including the status code, headers, and
body. The HttpContent class represents the HTTP body and content headers, such as Content-Type and
Content-Encoding . The content can be read using any of the ReadAs methods, such as ReadAsStringAsync and
ReadAsByteArrayAsync , depending upon the format of the data.
For more information about the HttpClient class, see Creating the HTTPClient Object.
HTTPWebRequest
Calling web services with HTTPWebRequest involves:
Creating the request instance for a particular URI.
Setting various HTTP properties on the request instance.
Retrieving an HttpWebResponse from the request.
Reading data out of the response.
For example, the following code retrieves data from the U.S. National Library of Medicine web service:
Assert.NotNull(content);
}
}
The above example creates an HttpWebRequest that will return data formatted as JSON. The data is returned in an
HttpWebResponse , from which a StreamReader can be obtained to read the data.
RestSharp
Another approach to consuming REST services is using the RestSharp library. RestSharp encapsulates HTTP
requests, including support for retrieving results either as raw string content or as a deserialized C# object. For
example, the following code makes a request to the U.S. National Library of Medicine web service, and retrieves
the results as a JSON formatted string:
DeserializeRxTerm is a method that will take the raw JSON string from the RestSharp.RestResponse.Content
property and convert it into a C# object. Deserializing data returned from web services is discussed later in this
article.
NSUrlConnection
In addition to classes available in the Mono base class library (BCL ), such as HttpWebRequest , and third party C#
libraries, such as RestSharp, platform-specific classes are also available for consuming web services. For example,
in iOS, the NSUrlConnection and NSMutableUrlRequest classes can be used.
The following code example shows how to call the U.S. National Library of Medicine web service using iOS
classes:
public RxTermNSURLConnectionDelegate()
: base()
{
_ResponseBuilder = new StringBuilder();
}
Generally, platform-specific classes for consuming web services should be limited to scenarios where native code is
being ported to C#. Where possible, web service access code should be portable so that it can be shared cross-
platform.
ServiceStack
Another option for calling web services is the Service Stack library. For example, the following code shows how to
use Service Stack’s IServiceClient.GetAsync method to issue a service request:
client.GetAsync<CustomersResponse>("",
(response) => {
foreach(var c in response.Customers) {
Console.WriteLine(c.CompanyName);
}
},
(response, ex) => {
Console.WriteLine(ex.Message);
});
IMPORTANT
While tools like ServiceStack and RestSharp make it easy to call and consume REST services, it is sometimes non-trivial to
consume XML or JSON that does not conform to the standard DataContract serialization conventions. If necessary, invoke
the request and handle the appropriate serialization explicitly using the ServiceStack.Text library discussed below.
However, it’s important to be aware that the System.Json tools load the entirety of the data into memory.
JSON.NET
The NewtonSoft JSON.NET library is a widely used library for serializing and deserializing JSON messages. The
following code example shows how to use JSON.NET to deserialize a JSON message into a C# object:
var term = new RxTerm();
var properties = JObject.Parse(json)["rxtermsProperties"];
term.BrandName = properties["brandName"].Value<string>();
term.DisplayName = properties["displayName"].Value<string>();
term.Synonym = properties["synonym"].Value<string>();;
term.FullName = properties["fullName"].Value<string>();;
term.FullGenericName = properties["fullGenericName"].Value<string>();;
term.Strength = properties["strength"].Value<string>();
term.RxCUI = properties["rxcui"].Value<string>();
ServiceStack.Text
ServiceStack.Text is a JSON serialization library designed to work with the ServiceStack library. The following code
example shows how to parse JSON using a ServiceStack.Text.JsonObject :
System.Xml.Linq
In the event of consuming an XML -based REST web service, LINQ to XML can be used to parse the XML and
populate a C# object inline, as demonstrated in the following code example:
file:///Users/myUserName/projects/MyProjectName/service.wsdl
This generates the proxy in the Web or Service References folder of the project. Since a proxy is generated code, it
should not be modified.
Manually Adding a Proxy to a Project
If you have an existing proxy that has been generated using compatible tools, this output can be consumed when
included as part of your project. In Visual Studio for Mac, use the Add files… menu option to add the proxy. In
addition, this requires System.Web.Services.dll to be referenced explicitly using the Add References… dialog.
Consuming the Proxy
The generated proxy classes provide methods for consuming the web service that use the Asynchronous
Programming Model (APM ) design pattern. In this pattern an asynchronous operation is implemented as two
methods named BeginOperationName and EndOperationName, which begin and end the asynchronous
operation.
The BeginOperationName method begins the asynchronous operation and returns an object that implements the
IAsyncResult interface. After calling BeginOperationName, an application can continue executing instructions on
the calling thread, while the asynchronous operation takes place on a thread pool thread.
For each call to BeginOperationName, the application should also call EndOperationName to get the results of the
operation. The return value of EndOperationName is the same type returned by the synchronous web service
method. The following code example shows an example of this:
The Task Parallel Library (TPL ) can simplify the process of consuming an APM begin/end method pair by
encapsulating the asynchronous operations in the same Task object. This encapsulation is provided by multiple
overloads of the Task.Factory.FromAsync method. This method creates a Task that executes the
TodoService.EndGetTodoItems method once the TodoService.BeginGetTodoItems method completes, with the null
parameter indicating that no data is being passed into the BeginGetTodoItems delegate. Finally, the value of the
TaskCreationOptions enumeration specifies that the default behavior for the creation and execution of tasks should
be used.
For more information about APM, see Asynchronous Programming Model and TPL and Traditional .NET
Framework Asynchronous Programming on MSDN.
For more information about consuming an ASMX service, see Consuming an ASP.NET Web Service (ASMX).
Generating a Proxy
A proxy must be generated to consume a WCF service, which allows the application to connect to the service. The
proxy is constructed by consuming service metadata that define the methods and associated service configuration.
This metadata is exposed in the form of a Web Services Description Language (WSDL ) document that is generated
by the web service. The proxy can be built by using the Microsoft WCF Web Service Reference Provider in Visual
Studio 2017 to add a service reference for the web service to a .NET Standard Library.
An alternative to creating the proxy using the Microsoft WCF Web Service Reference Provider in Visual Studio
2017 is to use the ServiceModel Metadata Utility Tool (svcutil.exe). For more information, see ServiceModel
Metadata Utility Tool (Svcutil.exe).
Configuring the Proxy
Configuring the generated proxy will generally take two configuration arguments (depending on SOAP 1.1/ASMX
or WCF ) during initialization: the EndpointAddress and/or the associated binding information, as shown in the
example below:
A binding is used to specify the transport, encoding, and protocol details required for applications and services to
communicate with each other. The BasicHttpBinding specifies that text-encoded SOAP messages will be sent over
the HTTP transport protocol. Specifying an endpoint address enables the application to connect to different
instances of the WCF service, provided that there are multiple published instances.
Consuming the Proxy
The generated proxy classes provide methods for consuming the web services that use the Asynchronous
Programming Model (APM ) design pattern. In this pattern, an asynchronous operation is implemented as two
methods named BeginOperationName and EndOperationName, which begin and end the asynchronous
operation.
The BeginOperationName method begins the asynchronous operation and returns an object that implements the
IAsyncResult interface. After calling BeginOperationName, an application can continue executing instructions on
the calling thread, while the asynchronous operation takes place on a thread pool thread.
For each call to BeginOperationName, the application should also call EndOperationName to get the results of the
operation. The return value of EndOperationName is the same type returned by the synchronous web service
method. The following code example shows an example of this:
public async Task<List<TodoItem>> RefreshDataAsync ()
{
...
var todoItems = await Task.Factory.FromAsync <ObservableCollection<TodoWCFService.TodoItem>> (
todoService.BeginGetTodoItems,
todoService.EndGetTodoItems,
null,
TaskCreationOptions.None);
...
}
The Task Parallel Library (TPL ) can simplify the process of consuming an APM begin/end method pair by
encapsulating the asynchronous operations in the same Task object. This encapsulation is provided by multiple
overloads of the Task.Factory.FromAsync method. This method creates a Task that executes the
TodoServiceClient.EndGetTodoItems method once the TodoServiceClient.BeginGetTodoItems method completes, with
the null parameter indicating that no data is being passed into the BeginGetTodoItems delegate. Finally, the value
of the TaskCreationOptions enumeration specifies that the default behavior for the creation and execution of tasks
should be used.
For more information about APM, see Asynchronous Programming Model and TPL and Traditional .NET
Framework Asynchronous Programming on MSDN.
For more information about consuming a WCF service, see Consuming a Windows Communication Foundation
(WCF ) Web Service.
Using Transport Security
WCF Services may employ transport level security to protect against interception of messages. The Xamarin
platform supports bindings that employ transport level security using SSL. However, there may be cases in which
the stack may need to validate the certificate, which results in unanticipated behavior. The validation can be
overridden by registering a ServerCertificateValidationCallback delegate before invoking the service, as
demonstrated in the following code example:
System.Net.ServicePointManager.ServerCertificateValidationCallback +=
(se, cert, chain, sslerror) => { return true; };
This maintains transport encryption while ignoring the server-side certificate validation. However, this approach
effectively disregards the trust concerns associated with the certificate and may not be appropriate. For more
information, see Using Trusted Roots Respectfully on mono-project.com.
Using Client Credential Security
WCF services may also require the service clients to authenticate using credentials. The Xamarin platform does not
support the WS -Security Protocol, which allows clients to send credentials inside the SOAP message envelope.
However, the Xamarin platform does support the ability to send HTTP Basic Authentication credentials to the
server by specifying the appropriate ClientCredentialType :
basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
client.ClientCredentials.UserName.UserName = @"foo";
client.ClientCredentials.UserName.Password = @"mrsnuggles";
In the example above, if you get the message “Ran out of trampolines of type 0” you can increase the number of
type 0 trampolines by adding the –aot “trampolines={number of trampolines}” argument to the build. For more
information, see Troubleshooting.
For more information about HTTP basic authentication, although in the context of a REST web service, see
Authenticating a RESTful Web Service.
Summary
This guide demonstrated how to consume different web service technologies. Topics covered include
communicating with REST services, SOAP services, and Windows Communication Foundation services.
Related Links
WebServices Sample
Web Services in Xamarin.Forms
ServiceModel Metadata Utility Tool (svcutil.exe)
BasicHttpBinding
Walkthrough - Working with WCF
5/8/2018 • 10 minutes to read • Edit Online
This walkthrough covers how a mobile application built with Xamarin can consume a WCF web service using the
BasicHttpBinding class.
It is a common requirement for mobile applications to be able to communicate with backend systems. There are
many choices and options for backend frameworks, one of which is Windows Communication Foundation (WCF ).
This walkthrough will provide an example of how a Xamarin mobile application can consume a WCF service using
the BasicHttpBinding class. The walkthrough includes the following topics:
1. Create a WCF Service - In this section we will create a very basic WCF service having two methods. The first
method will take a string parameter, while the other method will take a C# object. This section will also discuss
how to configure a developer's workstation to allow remote access to the WCF service.
2. Create a Xamarin.Android Application - Once the WCF service has been created, we will create a simple
Xamarin.Android application that will use the WCF service. This section will cover how to create a WCF service
proxy class to facilitate communication with the WCF service.
3. Create a Xamarin.iOS Application - The final part of this tutorial involves creating a simple Xamarin.iOS
application that will use the WCF service.
Requirements
This walkthrough assumes that you have some familiarity with creating and using WCF services.
namespace HelloWorldService
{
[DataContract]
public class HelloWorldData
{
[DataMember]
public bool SayHello { get; set; }
[DataMember]
public string Name { get; set; }
public HelloWorldData()
{
Name = "Hello ";
SayHello = false;
}
}
}
5. In Solution Explorer, open IHelloWorldService.cs and replace the code with the following code:
using System.ServiceModel;
namespace HelloWorldService
{
[ServiceContract]
public interface IHelloWorldService
{
[OperationContract]
string SayHelloTo(string name);
[OperationContract]
HelloWorldData GetHelloData(HelloWorldData helloWorldData);
}
}
This service provides two methods – one that takes a string for a parameter and another that takes a .NET
object.
6. In Solution Explorer, open HelloWorldService.cs and replace the code with the following code:
using System;
namespace HelloWorldService
{
public class HelloWorldService : IHelloWorldService
{
public HelloWorldData GetHelloData(HelloWorldData helloWorldData)
{
if (helloWorldData == null)
throw new ArgumentException("helloWorldData");
if (helloWorldData.SayHello)
helloWorldData.Name = "Hello World to {helloWorldData.Name}";
return helloWorldData;
}
7. In Solution Explorer, open App.config , update the name attribute of the <service> node, the contract
attribute of the <endpoint> node, and the baseAddress attribute of the <add> node:
8. Build and run the WCF service. The service will be hosted by the WCF test client:
9. With the WCF test client running, launch a browser and navigate to the endpoint for the WCF service:
IMPORTANT
The following section is only necessary if you need to accept remote connections on a Windows 10 workstation. The section
can be ignored if you have an alternate platform on which to deploy the WCF service.
Locate the site element with the name HelloWorldWcfHost . It should look something like the following
XML snippet:
We will need to add another binding to open up port 8734 to outside traffic. Add the following XML to the
bindings element, replacing the IP address with your own IP address:
This will configure IIS Express to accept HTTP traffic from any remote IP address on port 8734 on the
external IP address of the computer. This above snippet assumes the IP address of the computer running IIS
Express is 192.168.1.143. After the changes, the bindings element should look like the following:
<site name="HelloWorldWcfHost" id="2">
<application path="/" applicationPool="Clr4IntegratedAppPool">
<virtualDirectory path="/" physicalPath="\\vmware-host\Shared
Folders\tom\work\xamarin\code\private-samples\webservices\HelloWorld\HelloWorldWcfHost" />
</application>
<bindings>
<binding protocol="http" bindingInformation="*:8733:localhost" />
<binding protocol="http" bindingInformation="*:8734:192.168.1.143" />
</bindings>
</site>
4. Next, we need to configure IIS Express accept incoming connections on port 8734. Startup up an
administrative command prompt, and run this command:
> netsh http add urlacl url=http://192.168.1.143:9608/ user=everyone
5. The final step is to configure Windows Firewall to permit external traffic on port 8734. From an
administrative command prompt, run the following command:
> netsh advfirewall firewall add rule name="IISExpressXamarin" dir=in protocol=tcp localport=8734
profile=private remoteip=localsubnet action=allow
This command will allow incoming traffic on port 8734 from all devices on the same subnet as the
Windows 10 workstation.
You have created a very basic WCF service hosted in IIS Express that will accept incoming connections from other
devices or computers on our subnet. You can test this out by running your application and visiting
http://localhost:8733/Design_Time_Addresses/HelloWorldService/ on your workstation and
http://192.168.1.143:8734/Design_Time_Addresses/HelloWorldService/ from another computer on your subnet.
To allow IIS Express to keep running and serving the service, turn off the Edit and Continue option in Project
Properties > Web >Debuggers.
5. In Solution Explorer, open MainActivity.cs and replace existing code with the following code:
HelloWorldServiceClient _client;
Button _getHelloWorldDataButton;
TextView _getHelloWorldDataTextView;
Button _sayHelloWorldButton;
TextView _sayHelloWorldTextView;
...
}
SetContentView(Resource.Layout.Main);
InitializeHelloWorldServiceClient();
// This button will invoke the GetHelloWorldData - the method that takes a C# object as a
parameter.
_getHelloWorldDataButton = FindViewById<Button>(Resource.Id.getHelloWorldDataButton);
_getHelloWorldDataButton.Click += GetHelloWorldDataButtonOnClick;
_getHelloWorldDataTextView = FindViewById<TextView>(Resource.Id.getHelloWorldDataTextView);
// This button will invoke SayHelloWorld - this method takes a simple string as a parameter.
_sayHelloWorldButton = FindViewById<Button>(Resource.Id.sayHelloWorldButton);
_sayHelloWorldButton.Click += SayHelloWorldButtonOnClick;
_sayHelloWorldTextView = FindViewById<TextView>(Resource.Id.sayHelloWorldTextView);
}
The code above initializes the instance variables for the class and wires up some event handlers.
7. In MainActivity.cs , instantiate the client proxy class by adding the following two methods:
void InitializeHelloWorldServiceClient()
{
BasicHttpBinding binding = CreateBasicHttpBinding();
_client = new HelloWorldServiceClient(binding, Endpoint);
}
9. Run the application, ensure that the WCF service is running, and click on the two buttons. The application
will call the WCF asynchronously, provided that the Endpoint field is correctly set:
Creating a Xamarin.iOS Application
The WCF service proxy can be consumed by a Xamarin.iOS application, as follows:
1. In Visual Studio, add a new iPhone Single View Application project to the solution and name it
HelloWorld.iOS .
2. In the HelloWorld.iOS project, add a reference to the HelloWorldServiceProxy project, and a reference to the
System.ServiceModel namespace.
3. In Solution Explorer, double-click on Main.storyboard to open the file in the iOS designer. Then, add the
following UIButton and UITextView controls:
NAME TITLE
UITextView sayHelloWorldText
UITextView getHelloWorldDataText
After adding the controls, the UI should resemble the following screenshot:
getHelloWorldDataButton.TouchUpInside += GetHelloWorldDataButton_TouchUpInside;
sayHelloWorldButton.TouchUpInside += SayHelloWorldButton_TouchUpInside;
}
void InitializeHelloWorldServiceClient()
{
BasicHttpBinding binding = CreateBasicHttpBinding();
_client = new HelloWorldServiceClient(binding, Endpoint);
}
7. In ViewController.cs , add event handlers for the TouchUpInside events on the two UIButton instances:
async void GetHelloWorldDataButton_TouchUpInside(object sender, EventArgs e)
{
getHelloWorldDataText.Text = "Waiting for WCF...";
var data = new HelloWorldData
{
Name = "Mr. Chad",
SayHello = true
};
HelloWorldData result;
try
{
result = await _client.GetHelloDataAsync(data);
getHelloWorldDataText.Text = result.Name;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
8. Run the application, ensure that the WCF service is running, and click on the two buttons. The application
will call the WCF asynchronously, provided that the Endpoint field is correctly set:
Summary
This tutorial covered how to work with a WCF service in a mobile application using Xamarin.Android and
Xamarin.iOS. It showed how to create a WCF service and explained how to configure Windows 10 and IIS Express
to accept connections from remote devices. It then explained how to generate a WCF proxy client and
demonstrated how to use the proxy client in both Xamarin.Android and Xamarin.iOS applications.
Related Links
HelloWorld (sample)
Developing Service-Oriented Applications with WCF
How to: Create a Windows Communication Foundation Client
ServiceModel Metadata Utility Tool (svcutil.exe)
Deployment and Testing
5/25/2018 • 2 minutes to read • Edit Online
This section includes guides that explain how to test an application, optimize its performance, prepare it for release,
sign it with a certificate, and publish it to an app store.
Building Apps
This section describes how the build process works and explains how to build ABI-specific APKs.
Debugging
The guides in the section help you to debug your app using Android emulators, real Android devices, and the
debug log.
Environment
This article describes the Xamarin.Android execution environment and the Android system properties that
influence program execution.
GDB
This article explains how to use gdb for debugging a Xamarin.Android application.
Linking on Android
This article discusses the linking process used by Xamarin.Android to reduce the final size of an application. It
describes the various levels of linking that can be performed and provides some guidance and troubleshooting
advice to mitigate errors that might result from using the linker.
Xamarin.Android Performance
There are many techniques for increasing the performance of applications built with Xamarin.Android. Collectively
these techniques can greatly reduce the amount of work being performed by a CPU and the amount of memory
consumed by an application.
Publishing an Application
This series of articles explains the steps for public distribution of an application created with Xamarin.Android.
Distribution can take place via channels such as e-mail, a private web server, Google Play, or the Amazon App Store
for Android.
Application Package Size
4/12/2018 • 4 minutes to read • Edit Online
This article examines the constituent parts of a Xamarin.Android application package and the associated strategies
that can be used for efficient package deployment during debug and release stages of development.
Overview
Xamarin.Android uses a variety of mechanisms to minimize package size while maintaining an efficient debug and
release deploy process. In this article, we look at the Xamarin.Android release and debug deployment workflow
and how the Xamarin.Android platform ensures that we build and release small application packages.
Release Packages
To ship a fully contained application, the package must include the application, the associated libraries, the content,
the Mono runtime, and the required Base Class Library (BCL ) assemblies. For example, if we take the default
“Hello World” template, the contents of a complete package build would look like this:
15.8 MB is a larger download size than we’d like. The problem is the BCL libraries, as they include mscorlib,
System, and Mono.Android, which provide a lot of the necessary components to run your application. However,
they also provide functionality that you may not be using in your application, so it may be preferable to exclude
these components.
When we build an application for distribution, we execute a process, known as Linking, that examines the
application and removes any code that is not directly used. This process is similar to the functionality that Garbage
Collection provides for heap-allocated memory. But instead of operating over objects, linking operates over your
code. For example, there is a whole namespace in System.dll for sending and receiving email, but if your
application does not make use of this functionality, that code is just wasting space. After running the linker on the
Hello World application, our package now looks like this:
As we can see, this removes a significant amount of the BCL that was not being used. Note that the final BCL size
is dependent on what the application actually uses. For example, if we take a look at a more substantial sample
application called ApiDemo, we can see that the BCL component has increased in size because ApiDemo uses
more of the BCL than Hello, World does:
As illustrated here, your application package size will generally be about 2.9 MB larger than your application and
its dependencies.
Debug Packages
Things are handled slightly differently for debug builds. When redeploying repeatedly to a device, an application
needs to be as fast as possible, so we optimize debug packages for speed of deployment rather than size.
Android is relatively slow to copy and install a package, so we want the package size to be as small as possible. As
we discussed above, one possible way to minimize package size is via the linker. However, linking is slow and we
generally want to deploy only the parts of the application that have changed since the last deployment. To
accomplish this, we separate our application from the core Xamarin.Android components.
The first time we debug on device, we copy two large packages called Shared Runtime and Shared Platform.
Shared Runtime contains the Mono Runtime and BCL, while Shared Platform contains Android API level specific
assemblies:
Copying these core components is only done once as it takes quite a bit of time, but allows any subsequent
applications running in debug mode to utilize them. Finally, we copy the actual application, which is small and
quick:
4. Click the OK button to save the changes and close the Project Options dialog.
The next time the application is built for debug, the assemblies will be installed directly on the device (if they
haven't already been) and a smaller application package (that does not include the assemblies) will be installed on
the device. This will shorten the time it takes to get changes to the application up and running for testing.
By enduring the long first deploy of the shared runtime and shared platform, every time we make a change to the
application, we can deploy the new version quickly and painlessly, so we can have a fast change/deploy/run cycle.
Summary
In this article we examined the facets of Xamarin.Android Release and Debug profile packaging. Additionally, we
looked at the strategies that the Mono for Android platform uses to facilitate efficient package deployment during
debug and release stages of development.
Building Apps
4/12/2018 • 2 minutes to read • Edit Online
This section describes how the build process works and explains how to build ABI-specific APKs.
Build Process
This topic explains the steps and processes involved with the source code, resources, and assets of a
Xamarin.Android application and producing an APK that can be installed on Android devices.
Overview
The Xamarin.Android build process is responsible for gluing everything together: generating
Resource.designer.cs , supporting the AndroidAsset , AndroidResource , and other build actions, generating
Android-callable wrappers, and generating a .apk for execution on Android devices.
Application Packages
In broad terms, there are two types of Android application packages ( .apk files) which the Xamarin.Android
build system can generate:
Release builds, which are fully self-contained and don't require additional packages to execute. These are
the packages which would be provided to an App store.
Debug builds, which are not.
Not coincidentally, these match the MSBuild Configuration which produces the package.
Shared Runtime
The shared runtime is a pair of additional Android packages which provide the Base Class Library ( mscorlib.dll ,
etc.) and the Android binding library ( Mono.Android.dll , etc.). Debug builds rely upon the shared runtime in lieu
of including the Base Class Library and Binding assemblies within the Android application package, allowing the
Debug package to be smaller.
The shared runtime may be disabled in Debug builds by setting the $(AndroidUseSharedRuntime) property to
False .
Fast Deployment
Fast deployment works in concert with the shared runtime to further shrink the Android application package size.
This is done by not bundling the app's assemblies within the package. Instead, they are copied onto the target via
adb push . This process speeds up the build/deploy/debug cycle because if only assemblies are changed, the
package is not reinstalled. Instead, only the updated assemblies are re-synchronized to the target device.
Fast deployment is known to fail on devices which block adb from synchronizing to the directory
/data/data/@PACKAGE_NAME@/files/.__override__ .
Fast deployment is enabled by default, and may be disabled in Debug builds by setting the
$(EmbedAssembliesIntoApk) property to True .
MSBuild Projects
The Xamarin.Android build process is based on MSBuild, which is also the project file format used by Visual
Studio for Mac and Visual Studio. Ordinarily, users will not need to edit the MSBuild files by hand – the IDE
creates fully functional projects and updates them with any changes made, and automatically invoke build targets
as needed.
Advanced users may wish to do things not supported by the IDE's GUI, so the build process is customizable by
editing the project file directly. This page documents only the Xamarin.Android-specific features and
customizations – many more things are possible with the normal MSBuild items, properties and targets.
Build Targets
The following build targets are defined for Xamarin.Android projects:
Build – Builds the package.
Clean – Removes all files generated by the build process.
Install – Installs the package onto the default device or virtual device.
Uninstall – Uninstalls the package from the default device or virtual device.
SignAndroidPackage – Creates and signs the package ( .apk ). Use with /p:Configuration=Release to
generate self-contained "Release" packages.
UpdateAndroidResources – Updates the Resource.designer.cs file. This target is usually called by the
IDE when new resources are added to the project.
Build Properties
MSBuild properties control the behavior of the targets. They are specified within the project file, e.g.
MyApp.csproj, within an MSBuild PropertyGroup element.
Configuration – Specifies the build configuration to use, such as "Debug" or "Release". The Configuration
property is used to determine default values for other properties which determine target behavior.
Additional configurations may be created within your IDE.
By default, the Debug configuration will result in the Install and SignAndroidPackage targets creating a
smaller Android package which requires the presence of other files and packages to operate.
The default Release configuration will result in the Install and SignAndroidPackage targets creating an
Android package which is stand -alone, and may be used without installing any other packages or files.
DebugSymbols – A boolean value which determines whether the Android package is debuggable, in
combination with the $(DebugType) property. A debuggable package contains debug symbols, sets the
//application/@android:debuggable attribute to true , and automatically adds the INTERNET permission so
that a debugger can attach to the process. An application is debuggable if DebugSymbols is True and
DebugType is either the empty string or Full .
DebugType – Specifies the type of debug symbols to generate as part of the build, which also impacts
whether the Application is debuggable. Possible values include:
Full: Full symbols are generated. If the DebugSymbols MSBuild property is also True , then the
Application package is debuggable.
PdbOnly: "PDB" symbols are generated. The Application package will not be debuggable.
If DebugType is not set or is the empty string, then the DebugSymbols property controls whether or not the
Application is debuggable.
Install Properties
Install properties control the behavior of the Install and Uninstall targets.
AdbTarget – Specifies the Android target device the Android package may be installed to or removed
from. The value of this property is the same as the adb Target Device option:
# Install package onto emulator via -e
# Use `/Library/Frameworks/Mono.framework/Commands/msbuild` on OS X
MSBuild /t:Install ProjectName.csproj /p:AdbTarget=-e
Packaging Properties
Packaging properties control the creation of the Android package, and are used by the Install and
SignAndroidPackage targets. The Signing Properties are also relevant when packaging Release applications.
AndroidApkSigningAlgorithm – A string value which specifies the signing algorithm to use with
jarsigner -sigalg .
When True, such types will generate an XA4212 error, otherwise a XA4212 warning will be generated.
Support for this property was added in Xamarin.Android 8.1.
This property is True by default.
AndroidFastDeploymentType – A : (colon)-separated list of values to control what types can be
deployed to the Fast Deployment directory on the target device when the $(EmbedAssembliesIntoApk)
MSBuild property is False . If a resource is fast deployed, it is not embedded into the generated .apk ,
which can speed up deployment times. (The more that is fast deployed, then the less frequently the .apk
needs to be rebuilt, and the install process can be faster.) Valid values include:
Assemblies : Deploy application assemblies.
: Deploy .dex files, Android Resources, and Android Assets. This value can only be used
Dexes
on devices running Android 4.4 or later (API -19).
The default value is Assemblies .
Experimental. Added in Xamarin.Android 6.1.
AndroidApplicationJavaClass – The full Java class name to use in place of android.app.Application
when a class inherits from Android.App.Application.
This property is generally set by other properties, such as the $(AndroidEnableMultiDex) MSBuild property.
Added in Xamarin.Android 6.1.
AndroidHttpClientHandlerType – Controls the default System.Net.Http.HttpMessageHandler
implementation which will be used by the System.Net.Http.HttpClient default constructor. The value is an
assembly-qualified type name of an HttpMessageHandler subclass, suitable for use with
System.Type.GetType(string) .
<AndroidLinkMode>SdkOnly</AndroidLinkMode>
<AndroidLinkSkip>Assembly1;Assembly2</AndroidLinkSkip>
AndroidManagedSymbols – A boolean property that controls whether sequence points are generated
so that file name and line number information can be extracted from Release stack traces.
Added in Xamarin.Android 6.1.
AndroidManifest – Specifies a filename to use as the template for the app's AndroidManifest.xml . During
the build, any other necessary values will be merged into to produce the actual AndroidManifest.xml . The
$(AndroidManifest) must contain the package name in the /manifest/@package attribute.
AndroidSdkBuildToolsVersion – The Android SDK build-tools package provides the aapt and zipalign
tools, among others. Multiple different versions of the build-tools package may be installed
simultaneously. The build-tools package chosen for packaging is done by checking for and using a
"preferred" build-tools version if it is present; if the "preferred" version is not present, then the highest
versioned installed build-tools package is used.
The $(AndroidSdkBuildToolsVersion) MSBuild property contains the preferred build-tools version. The
Xamarin.Android build system provides a default value in Xamarin.Android.Common.targets , and the default
value may be overridden within your project file to choose an alternate build-tools version, if (for example)
the latest aapt is crashing out while a previous aapt version is known to work.
AndroidSupportedAbis – A string property that contains a semicolon ( ; )-delimited list of ABIs which
should be included into the .apk .
Supported values include:
armeabi
armeabi-v7a
x86
arm64-v8a : Requires Xamarin.Android 5.1 and later.
x86_64 : Requires Xamarin.Android 5.1 and later.
AndroidUseSharedRuntime – A boolean property that is determines whether the shared runtime
packages are required in order to run the Application on the target device. Relying on the shared runtime
packages allows the Application package to be smaller, speeding up the package creation and deployment
process, resulting in a faster build/deploy/debug turnaround cycle.
This property should be True for Debug builds, and False for Release projects.
AotAssemblies – A boolean property that determines whether or not assemblies will be Ahead-of-Time
compiled into native code and included in the .apk .
Support for this property was added in Xamarin.Android 5.1.
This property is False by default.
EmbedAssembliesIntoApk – A boolean property that determines whether or not the app's assemblies
should be embedded into the Application package.
This property should be True for Release builds and False for Debug builds. It may need to be True in
Debug builds if Fast Deployment doesn't support the target device.
When this property is False , then the $(AndroidFastDeploymentType) MSBuild property also controls what
will be embedded into the .apk , which can impact deployment and rebuild times.
EnableLLVM – A boolean property that determines whether or not LLVM will be used when Ahead-of-
Time compiling assemblies into native code.
Support for this property was added in Xamarin.Android 5.1.
This property is False by default.
This property is ignored unless the $(AotAssemblies) MSBuild property is True .
EnableProguard – A boolean property that determines whether or not proguard is run as part of the
packaging process to link Java code.
Support for this property was added in Xamarin.Android 5.1.
This property is False by default.
When True , ProguardConfiguration files will be used to control proguard execution.
JavaMaximumHeapSize – Specifies the value of the java -Xmx parameter value to use when building
the .dex file as part of the packaging process. If not specified, then the -Xmx option is not provided to
java.
Specifying this property is necessary if the _CompileDex target throws a java.lang.OutOfMemoryError .
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
JavaOptions – Specifies additional command-line options to pass to java when building the .dex file.
MandroidI18n – Specifies the internationalization support included with the Application, such as collation
and sorting tables. The value is a comma- or semicolon-separated list of one or more of the following
case-insensitive values:
None: Include no additional encodings.
All: Include all available encodings.
CJK: Include Chinese, Japanese, and Korean encodings such as Japanese (EUC ) [enc-jp, CP51932],
Japanese (Shift-JIS ) [iso-2022-jp, shift_jis, CP932], Japanese (JIS ) [CP50220], Chinese Simplified
(GB2312 ) [gb2312, CP936], Korean (UHC ) [ks_c_5601-1987, CP949], Korean (EUC ) [euc-kr,
CP51949], Chinese Traditional (Big5 ) [big5, CP950], and Chinese Simplified (GB18030 ) [GB18030,
CP54936].
MidEast: Include Middle-Eastern encodings such as Turkish (Windows) [iso-8859-9, CP1254],
Hebrew (Windows) [windows-1255, CP1255], Arabic (Windows) [windows-1256, CP1256], Arabic
(ISO ) [iso-8859-6, CP28596], Hebrew (ISO ) [iso-8859-8, CP28598], Latin 5 (ISO ) [iso-8859-9,
CP28599], and Hebrew (Iso Alternative) [iso-8859-8, CP38598].
Other: Include Other encodings such as Cyrillic (Windows) [CP1251], Baltic (Windows) [iso-8859-
4, CP1257], Vietnamese (Windows) [CP1258], Cyrillic (KOI8 -R ) [koi8-r, CP1251], Ukrainian (KOI8 -
U ) [koi8-u, CP1251], Baltic (ISO ) [iso-8859-4, CP1257], Cyrillic (ISO ) [iso-8859-5, CP1251], ISCII
Davenagari [x-iscii-de, CP57002], ISCII Bengali [x-iscii-be, CP57003], ISCII Tamil [x-iscii-ta,
CP57004], ISCII Telugu [x-iscii-te, CP57005], ISCII Assamese [x-iscii-as, CP57006], ISCII Oriya [x-
iscii-or, CP57007], ISCII Kannada [x-iscii-ka, CP57008], ISCII Malayalam [x-iscii-ma, CP57009],
ISCII Gujarati [x-iscii-gu, CP57010], ISCII Punjabi [x-iscii-pa, CP57011], and Thai (Windows)
[CP874].
Rare: Include Rare encodings such as IBM EBCDIC (Turkish) [CP1026], IBM EBCDIC (Open
Systems Latin 1 ) [CP1047], IBM EBCDIC (US -Canada with Euro ) [CP1140], IBM EBCDIC
(Germany with Euro ) [CP1141], IBM EBCDIC (Denmark/Norway with Euro ) [CP1142], IBM
EBCDIC (Finland/Sweden with Euro ) [CP1143], IBM EBCDIC (Italy with Euro ) [CP1144], IBM
EBCDIC (Latin America/Spain with Euro ) [CP1145], IBM EBCDIC (United Kingdom with Euro )
[CP1146], IBM EBCDIC (France with Euro ) [CP1147], IBM EBCDIC (International with Euro )
[CP1148], IBM EBCDIC (Icelandic with Euro ) [CP1149], IBM EBCDIC (Germany ) [CP20273], IBM
EBCDIC (Denmark/Norway ) [CP20277], IBM EBCDIC (Finland/Sweden) [CP20278], IBM EBCDIC
(Italy ) [CP20280], IBM EBCDIC (Latin America/Spain) [CP20284], IBM EBCDIC (United Kingdom )
[CP20285], IBM EBCDIC (Japanese Katakana Extended ) [CP20290], IBM EBCDIC (France)
[CP20297], IBM EBCDIC (Arabic) [CP20420], IBM EBCDIC (Hebrew ) [CP20424], IBM EBCDIC
(Icelandic) [CP20871], IBM EBCDIC (Cyrillic - Serbian, Bulgarian) [CP21025], IBM EBCDIC (US -
Canada ) [CP37], IBM EBCDIC (International) [CP500], Arabic (ASMO 708 ) [CP708], Central
European (DOS ) [CP852], Cyrillic (DOS ) [CP855], Turkish (DOS ) [CP857], Western European (DOS
with Euro ) [CP858], Hebrew (DOS ) [CP862], Arabic (DOS ) [CP864], Russian (DOS ) [CP866], Greek
(DOS ) [CP869], IBM EBCDIC (Latin 2 ) [CP870], and IBM EBCDIC (Greek) [CP875].
West: Include Western encodings such as Western European (Mac) [macintosh, CP10000],
Icelandic (Mac) [x-mac-icelandic, CP10079], Central European (Windows) [iso-8859-2, CP1250],
Western European (Windows) [iso-8859-1, CP1252], Greek (Windows) [iso-8859-7, CP1253],
Central European (ISO ) [iso-8859-2, CP28592], Latin 3 (ISO ) [iso-8859-3, CP28593], Greek (ISO )
[iso-8859-7, CP28597], Latin 9 (ISO ) [iso-8859-15, CP28605], OEM United States [CP437],
Western European (DOS ) [CP850], Portuguese (DOS ) [CP860], Icelandic (DOS ) [CP861], French
Canadian (DOS ) [CP863], and Nordic (DOS ) [CP865].
<MandroidI18n>West</MandroidI18n>
MonoSymbolArchive – A boolean property which controls whether .mSYM artifacts are created for later
use with mono-symbolicate , to extract “real” filename and line number information from Release stack
traces.
This is True by default for “Release” apps which have debugging symbols enabled:
$(EmbedAssembliesIntoApk) is True, $(DebugSymbols) is True, and $(Optimize) is True.
Added in Xamarin.Android 7.1.
AndroidVersionCodePattern – A string property which allows the developer to customize the
versionCode in the manifest. See Creating the Version Code for the APK for information on deciding a
versionCode .
Some examples, if abi is armeabi and versionCode in the manifest is 123 , {abi}{versionCode} will
produce a versionCode of 1123 when $(AndroidCreatePackagePerAbi) is True, otherwise will produce a
value of 123. If abi is x86_64 and versionCode in the manifest is 44 . This will produce 544 when
$(AndroidCreatePackagePerAbi) is True, otherwise will produce a value of 44 .
If we include a left padding format string {abi}{versionCode:0000} , it would produce 50044 because we
are left padding the versionCode with 0 . Alternatively, you can use the decimal padding such as
{abi}{versionCode:D4} which does the same as the previous example.
Only '0' and 'Dx' padding format strings are supported since the value MUST be an integer.
Pre-defined key items
abi – Inserts the targeted abi for the app
1 – armeabi
2 – armeabi-v7a
3 – x86
4 – arm64-v8a
5 – x86_64
minSDK – Inserts the minimum supported Sdk value from the AndroidManifest.xml or 11 if none
is defined.
versionCode – Uses the version code directly from Properties\AndroidManifest.xml .
You can define custom items using the $(AndroidVersionCodeProperties) property (defined next).
By default the value will be set to {abi}{versionCode:D6} . If a developer wants to keep the old behavior
you can override the default by setting the $(AndroidUseLegacyVersionCode) property to true
Added in Xamarin.Android 7.2.
AndroidVersionCodeProperties – A string property which allows the developer to define custom items
to use with the AndroidVersionCodePattern . They are in the form of a key=value pair. All items in the
value should be integer values. For example: screen=23;target=$(_SupportedApiLevel) . As you can see you
can make use of existing or custom MSBuild properties in the string.
Added in Xamarin.Android 7.2.
AndroidUseLegacyVersionCode – A boolean property will allows the developer to revert the
versionCode calculation back to its old pre Xamarin.Android 8.2 behavior. This should ONLY be used for
developers with existing applications in the Google Play Store. It is highly recommended that the new
$(AndroidVersionCodePattern) property is used.
By default, the signing target generates a new debug-signing key if necessary. If you wish to use a specific key, for
example on a build server, the following MSBuild properties can be used:
AndroidKeyStore – A boolean value which indicates whether custom signing information should be used.
The default value is False , meaning that the default debug-signing key will be used to sign packages.
AndroidSigningKeyAlias – Specifies the alias for the key in the keystore. This is the keytool -alias value
used when creating the keystore.
AndroidSigningKeyPass – Specifies the password of the key within the keystore file. This is the value
entered when keytool asks Enter key password for $(AndroidSigningKeyAlias).
AndroidSigningKeyStore – Specifies the filename of the keystore file created by keytool . This
corresponds to the value provided to the keytool -keystore option.
AndroidSigningStorePass – Specifies the password to $(AndroidSigningKeyStore) . This is the value
provided to keytool when creating the keystore file and asked Enter keystore password:.
For example, consider the following keytool invocation:
$ keytool -genkey -v -keystore filename.keystore -alias keystore.alias -keyalg RSA -keysize 2048 -validity
10000
Enter keystore password: keystore.filename password
Re-enter new password: keystore.filename password
...
Is CN=... correct?
[no]: yes
Generating 2,048 bit RSA key pair and self-signed certificate (SHA1withRSA) with a validity of 10,000 days
for: ...
Enter key password for keystore.alias
(RETURN if same as keystore password): keystore.alias password
[Storing filename.keystore]
AndroidDebugKeyAlgorithm – Specifies the default algorithm to use for the debug.keystore . It defaults
to RSA .
AndroidDebugKeyValidity – Specifies the default validity to use for the debug.keystore . It defaults to
10950 or 30 * 365 or 30 years .
Build Actions
Build actions are applied to files within the project and control how the file is processed.
AndroidEnvironment
Files with a Build action of AndroidEnvironment are used to initialize environment variables and system properties
during process startup. The AndroidEnvironment Build action may be applied to multiple files, and they will be
evaluated in no particular order (so don't specify the same environment variable or system property in multiple
files).
AndroidJavaSource
Files with a Build action of AndroidJavaSource are Java source code which will be included in the final Android
package.
AndroidJavaLibrary
Files with a Build action of AndroidJavaLibrary are Java Archives ( .jar files) which will be included in the final
Android package.
AndroidResource
All files with an AndroidResource build action are compiled into Android resources during the build process and
made accessible via $(AndroidResgenFile) .
<ItemGroup>
<AndroidResource Include="Resources\values\strings.xml" />
</ItemGroup>
More advanced users might perhaps wish to have different resources used in different configurations but with
the same effective path. This can be achieved by having multiple resource directories and having files with the
same relative paths within these different directories, and using MSBuild conditions to conditionally include
different files in different configurations. For example:
<ItemGroup Condition="'$(Configuration)'!='Debug'">
<AndroidResource Include="Resources\values\strings.xml" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)'=='Debug'">
<AndroidResource Include="Resources-Debug\values\strings.xml"/>
</ItemGroup>
<PropertyGroup>
<MonoAndroidResourcePrefix>Resources;Resources-Debug<MonoAndroidResourcePrefix>
</PropertyGroup>
LogicalName – Specifies the resource path explicitly. Allows “aliasing” files so that they will be available as
multiple distinct resource names.
<ItemGroup Condition="'$(Configuration)'!='Debug'">
<AndroidResource Include="Resources/values/strings.xml"/>
</ItemGroup>
<ItemGroup Condition="'$(Configuration)'=='Debug'">
<AndroidResource Include="Resources-Debug/values/strings.xml">
<LogicalName>values/strings.xml</LogicalName>
</AndroidResource>
</ItemGroup>
AndroidNativeLibrary
Native libraries are added to the build by setting their Build action to AndroidNativeLibrary .
Note that since Android supports multiple Application Binary Interfaces (ABIs), the build system must know
which ABI the native library is built for. There are two ways this can be done:
1. Path "sniffing".
2. Using the Abi item attribute.
With path sniffing, the parent directory name of the native library is used to specify the ABI that the library
targets. Thus, if you add lib/armeabi/libfoo.so to the build, then the ABI will be "sniffed" as armeabi .
Item Attribute Name
Abi – Specifies the ABI of the native library.
<ItemGroup>
<AndroidNativeLibrary Include="path/to/libfoo.so">
<Abi>armeabi</Abi>
</AndroidNativeLibrary>
</ItemGroup>
AndroidAarLibrary
The Build action of AndroidAarLibrary should be used to directly reference .aar files. This build action will be most
commonly used by Xamarin Components. Namely to include references to .aar files which are required to get
Google Play and other services working.
Files with this Build action will be treated in a similar fashion too the embedded resources found in Library
projects. The .aar will be extracted into the intermediate directory. Then any assets, resource and .jar files will be
included in the appropriate item groups.
Content
The normal Content Build action is not supported (as we haven't figured out how to support it without a possibly
costly first-run step).
Starting in Xamarin.Android 5.1, attempting to use the @(Content) Build action will result in a XA0101 warning.
LinkDescription
Files with a LinkDescription build action are used to control linker behavior.
ProguardConfiguration
Files with a ProguardConfiguration build action contain options which are used to control proguard behavior.
For more information about this build action, see ProGuard.
These files are ignored unless the $(EnableProguard) MSBuild property is True .
Target Definitions
The Xamarin.Android-specific parts of the build process are defined in
$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets , but normal language-specific targets
such as Microsoft.CSharp.targets are also required to build the assembly.
The following build properties must be set before importing any language targets:
<PropertyGroup>
<TargetFrameworkIdentifier>MonoDroid</TargetFrameworkIdentifier>
<MonoDroidVersion>v1.0</MonoDroidVersion>
<TargetFrameworkVersion>v2.2</TargetFrameworkVersion>
</PropertyGroup>
All of these targets and properties can be included for C# by importing Xamarin.Android.CSharp.targets:
This document will discuss how to build an APK that will target a single ABI using Xamarin.Android.
Overview
In some situations it may be advantageous for an application to have multiple APKs - each APK is signed with the
same keystore and shares the same package name but it is compiled for a specific device or Android
configuration. This is not the recommended approach - it is much simpler to have one APK that can support
multiple devices and configurations. There are some situations where creating multiple APKs can be useful, such
as:
Reduce the size of the APK - Google Play imposes a 100MB size limit on APK files. Creating device
specific APK's can reduce the size of the APK as you only need to supply a subset of assets and resources
for the application.
Support different CPU architectures - If your application has shared libraries for specific CPU's, you can
distribute only the shared libraries for that CPU.
Multiple APKs can complicate distribution - a problem that is addressed by Google Play. Google Play will ensure
that the correct APK is delivered to a device based on the application's version code and other metadata contained
with AndroidManifest.XML. For specific details and restrictions on how Google Play supports multiple APKs for
an application, consult Google's documentation on multiple APK support.
This guide will address how to script the building multiple APKs for a Xamarin.Android application, each APK
targeting a specific ABI. It will cover the following topics:
1. Create a unique version code for the APK.
2. Create a temporary version of AndroidManifest.XML that will be used for this APK.
3. Build the application using the AndroidManifest.XML from the previous step.
4. Prepare the APK for release by signing and zip-aligning it.
At the end of this guide is a walkthrough that will demonstrate how to script these steps using Rake.
Creating the Version Code for the APK
Google recommends a particular algorithm for the version code that uses a seven digit version code (please see
the section Using a version code scheme in the Multiple APK support document). By expanding this version code
scheme to eight digits, it is possible to include some ABI information into the version code that will ensure that
Google Play will distribute the correct APK to a device. The following list explains this eight digit version code
format (indexed from left to right):
Index 0 (red in diagram below ) – An integer for the ABI:
1 – armeabi
2 – armeabi-v7a
6 – x86
Index 1-2 (orange in diagram below ) – The minimum API level supported by the application.
Index 3-4 (blue in diagram below ) – The screen sizes supported:
1 – small
2 – normal
3 – large
4 – xlarge
Index 5-7 (green in diagram below ) – A unique number for the version code. This is set by the developer. It
should increase for each public release of the application.
The following diagram illustrates the position of each code described in the above list:
Google Play will ensure that the correct APK is delivered to the device based on the versionCode and APK
configuration. The APK with the highest version code will be delivered to the device. As an example, an application
could have three APKs with the following version codes:
11413456 - The ABI is armeabi ; targetting API level 14; small to large screens; with a version number of 456.
21423456 - The ABI is armeabi-v7a ; targetting API level 14; normal & large screens; with a version number of
456.
61423456 - The ABI is x86 ; targetting API level 14; normal & large screens; with a version number of 456.
To continue on with this example, imagine that a bug was fixed which was specific to armeabi-v7a . The app
version increases to 457, and an new APK is built with the android:versionCode set to 21423457. The
versionCodes for the armeabi and x86 versions would remain the same.
Now imagine that the x86 version receives some updates or bug fixes that target a newer API (API level 19),
making this version 500 of the app. The new versionCode would change to 61923500 while the
armeabi/armeabi-v7a remain unchanged. At this point in time, the version codes would be:
11413456 - The ABI is armeabi ; targetting API level 14; small to large screens; with a version name of 456.
21423457 - The ABI is armeabi-v7a ; targetting API level 14; normal & large screens; with a version name of
457.
61923500 - The ABI is x86 ; targetting API level 19; normal & large screens; with a version name of 500.
Maintaining these version codes manually can be a significant burden on the developer. The process of calculating
the correct android:versionCode and then building the APK's should be automated. An example of how to do so
will be covered in the walkthrough at the end of this document.
Create A Temporary AndroidManifest.XML
Although not strictly necessary, creating an temporary AndroidManifest.XML for each ABI can help prevent
issues that might arise with information leaking from one APK to the other. For example, it is crucial that the
android:versionCode attribute is unique for each APK.
How this is done depends on the scripting system involved, but typically involves taking a copy of the Android
manifest used during development, modifying it, and then using that modify manifest during the build process.
Compiling the APK
Building the APK per ABI is best accomplished by using either xbuild or msbuild as shown in the following
sample command line:
/p:IntermediateOutputPath=obj.<TARGET_ABI>/ – This is the directory that will hold the intermediate files that
are created as a part of the build. If necessary, Xamarin.Android will create a directory named after the ABI,
such as obj.armeabi-v7a . It is recommended to use one folder for each ABI as this will prevent issues that
make result with files "leaking" from one build to another. Notice that this value is terminated with a
directory separator (a / in the case of OS X).
/p:AndroidManifest – This property specifies the path to the AndroidManifest.XML file that will be used
during the build.
/p:OutputPath=bin.<TARGET_ABI> – This is the directory that will house the final APK. Xamarin.Android will
create a directory named after the ABI, for example bin.armeabi-v7a .
/p:Configuration=Release – Perform a Release build of the APK. Debug builds may not be uploaded to
Google Play.
<CS_PROJ FILE> – This is the path to the .csproj file for the Xamarin.Android project.
Sign and Zipalign The APK
It is necessary to sign the APK before it can be distributed via Google Play. This can be performed by using the
jarsigner application that is a part of the Java Developer's Kit. The following command line demonstrats how to
use jarsigner at the command line:
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore <PATH/TO/KEYSTORE> -storepass <PASSWORD> -
signedjar <PATH/FOR/SIGNED_JAR> <PATH/FOR/JAR/TO/SIGN> <NAME_OF_KEY_IN_KEYSTORE>
All Xamarin.Android applications must be zip-aligned before they can be run on a device. This is the format of the
command line to use:
$ rake build
==> Building an APK for ABI armeabi with ./Properties/AndroidManifest.xml.armeabi, android:versionCode =
10814120.
==> Building an APK for ABI x86 with ./Properties/AndroidManifest.xml.x86, android:versionCode = 60814120.
==> Building an APK for ABI armeabi-v7a with ./Properties/AndroidManifest.xml.armeabi-v7a, android:versionCode
= 20814120.
Once the rake task has completed, there will be three bin folders with the file xamarin.helloworld.apk . The next
screenshot shows each of these folders with their contents:
NOTE
The build process outlined in this guide may be implemented in one of many different build systems. Although we don't
have a pre-written example, it should also be possible with Powershell / psake or Fake.
Summary
This guide provided some suggestions with how to create Android APK's that target a specify ABI. It also
discussed one possible scheme for creating android:versionCodes that will identify the CPU architecture that the
APK is intended for. The walkthrough included a sample project that has it's build scripted using Rake.
Related Links
OneABIPerAPK (sample)
Publishing an Application
Multiple APK Support for Google Play
Command Line Emulator
4/12/2018 • 2 minutes to read • Edit Online
On macOS
The reason for needing the partition size is to allow the emulator to have plenty of space to get the
Xamarin.Android platform installed on the emulator as by default the size of the emulator is small.
You can find out more information on extra parameters on the Android site here -
http://developer.android.com/guide/developing/tools/emulator.html
Debugging
6/25/2018 • 2 minutes to read • Edit Online
Debugging Overview
Developing Android applications requires running the application, either on physical hardware or using an
emulator. Using hardware is the best approach, but not always the most practical. In many cases, it can be simpler
and more cost effective to simulate/emulate Android hardware using one of the emulators described below.
Debugging on the Android Emulator
This article explains how launch the Android emulator from Visual Studio and run your app in a virtual device.
Debugging on a Device
This article shows how to configure a physical Android device so that Xamarin.Android application can be
deployed to it directly from either Visual Studio or Visual Studio or Mac.
Android Debug Log
One very common trick developers use to debug their applications is using Console.WriteLine . However, on a
mobile platform like Android there is no console. Android devices provides a log that you will likely need to utilize
while writing apps. This is sometimes referred to as logcat due to the command typed to retrieve it. This article
describes how to use logcat.
WARNING
Note that the Xamarin Android Player has been deprecated. For more information, see the announcement in this blog
post. In addition, the Visual Studio Android Emulator has been deprecated as of Visual Studio 2017.
Debugging on the Android Emulator
6/25/2018 • 4 minutes to read • Edit Online
In this guide, you will learn how to launch a virtual device in the Android Emulator to debug and test your app.
Overview
The Android Emulator (installed as part of the Mobile development with .NET workload), can be run in a
variety of configurations to simulate different Android devices. Each one of these configurations is created as a
virtual device. In this guide, you will learn how to launch the emulator from Visual Studio and run your app in a
virtual device. For information about configuring the Android Emulator and creating new virtual devices, see
Android Emulator Setup.
Typically, you would select the VisualStudio_android-23_x86_phone virtual device to test and debug a phone
app. If one of these pre-configured virtual devices meets your requirements (i.e., matches your app's target API
level), skip to Launching the Emulator to begin running your app in the emulator. (If you are not yet familiar with
Android API levels, see Understanding Android API Levels.)
If your Xamarin.Android project is using a Target Framework level that is incompatible with the available virtual
devices, the drop-down menu lists the unusable virtual devices under Unsupported Devices. For example, the
following project has a Target Framework set to Android 7.1 Nougat (API 25), which is incompatible with the
Android 6.0 virtual devices that are listed in this example:
You can click Change Minimum Android Target to change the project's Minimum Android Version so that it
matches the API level of the available virtual devices. Alternately, you can use the Android Device Manager to
create new virtual devices that support your target API level. Before you can configure virtual devices for a new
API level, you must first install the corresponding system images for that API level (see Setting up the Android
SDK for Xamarin.Android).
After the emulator starts, Xamarin.Android will deploy the app to the emulator. The emulator runs the app with
the configured virtual device image. An example screenshot of the Android Emulator is displayed below. In this
example, the emulator is running a blank app called MyApp:
The emulator may be left running: it is not necessary to shut it down and wait for it to restart each time the app is
launched. The first time a Xamarin.Android app is run in the emulator, the Xamarin.Android shared runtime for
the targetted API level is installed, followed by the application. The runtime installation may take a few moments,
so please be patient. Installation of the runtime takes place only when the first Xamarin.Android app is deployed
to the emulator – subsequent deployments are faster because only the app is copied to the emulator.
Quick Boot
Newer versions of the Android Emulator include a feature called Quick Boot that launches the emulator in only a
few seconds. When you close the emulator, it takes a snapshot of the virtual device state so that it can be quickly
restored from that state when it is restarted. To access this feature, you will need the following:
Android Emulator version 27.0.2 or later
Android SDK Tools version 26.1.1 or later
When the above-listed versions of the emulator and SDK tools are installed, the Quick Boot feature is enabled by
default.
The first cold boot of the virtual device takes place without a speed improvement because a snapshot has not yet
been created:
When you exit out of the emulator, Quick Boot saves the state of the emulator in a snapshot:
Subsequent virtual device starts are much faster because the emulator simply restores the state at which you
closed the emulator.
Troubleshooting
For tips and workarounds for common emulator problems, see Android Emulator Troubleshooting.
Summary
This guide explained the process for configuring the Android Emulator to run and test Xamarin.Android apps. It
described the steps for launching the emulator using pre-configured virtual devices, and it provided the steps for
deploying an application to the emulator from Visual Studio.
For more information about using the Android Emulator, see the following Android Developer topics:
Navigating on the Screen
Performing Basic Tasks in the Emulator
Working with Extended Controls, Settings, and Help
Run the emulator with Quick Boot
Debug on Device
4/12/2018 • 2 minutes to read • Edit Online
This article explains how to debug a Xamarin.Android application on a physical Android device.
Debug Application
Once a device is connected to your computer, debugging a Xamarin.Android application is done in the same way
as any other Xamarin product or .NET application. Ensure that the Debug configuration and the external device is
selected in the IDE, this will ensure that the necessary debug symbols are available and that the IDE can connect to
the running application:
Visual Studio
Visual Studio for Mac
Once the device has been selected, Xamarin.Android will connect to the device, deploy the application, and then
run it. When the breakpoint is reached, the debugger will stop the application, allowing the application to be
debugged in a fashion similar to any other C# application:
Summary
In this document discussed how to debug a Xamarin.Android application by setting a breakpoint and selecting the
target device.
Related Links
Set Up Device for Development
Setting the Debuggable Attribute
Android Debug Log
6/25/2018 • 5 minutes to read • Edit Online
One very common trick developers use to debug their applications is to make calls to Console.WriteLine .
However, on a mobile platform like Android there is no console. Android devices provides a log that you can use
while writing apps. This is sometimes referred to as logcat due to the command that you type to retrieve it. Use
the Debug Log tool to view the logged data.
NOTE
The Debug Log tool does not work with Xamarin Live Player.
The Debug Log does not display log messages that are generated while the app is running standalone on the
device (i.e., while it is disconnected from Visual Studio).
Alternately, launch the Device Log tool from one of the following menu selections:
View > Other Windows > Device Log
Tools > Android > Device Log
The following screenshot illustrates the various parts of the Debug Tool window:
Device Selector – Selects which physical device or running emulator to monitor.
Log Entries – A table of log messages from logcat.
Clear Log Entries – Clears all current log entries from the table.
Play/Pause – Toggles between updating or pausing the display of new log entries.
Stop – Halts the display of new log entries.
Search Box – Enter search strings in this box to filter for a subset of log entries.
When the Debug Log tool window is displayed, use the device pull-down menu to choose the Android device to
monitor:
After the device is selected, the Device Log tool automatically adds log entries from a running app – these log
entries are shown in the the table of log entries. Switching between devices stops and starts device logging. Note
that an Android project must be loaded before any devices will appear in the device selector. If the device does not
appear in the device selector, verify that it is available in the Visual Studio device drop-down menu next to the
Start button.
If more than one device is attached, the device must be explicitly identified. For example adb -d logcat displays
the log of the only physical device connected, while adb -e logcat shows the log of the only emulator running.
More commands can be found by entering adb and reading the help messages.
It is also possible to use Console.WriteLine to write to the Debug Log – these messages appear in logcat with a
slightly different output format (this technique is particularly useful when debugging Xamarin.Forms apps on
Android):
Interesting Messages
When reading the log (and especially when providing log snippets to others), perusing the log file in its entirety is
often too cumbersome. To make it easier to navigate through log messages, start by looking for a log entry that
resembles the following:
In particular, look for a line matching the regular expression that also contains the name of the application
package:
^I.*ActivityManager.*Starting: Intent
This is the line which corresponds to the start of an activity, and most (but not all) of the following messages
should relate to the application.
Notice that every message contains the process identifier (pid) of the process generating the message. In the
above ActivityManager message, process 12944 generated the message. To determine which process is the
process of the application being debugged, look for the mono.MonoRuntimeProvider message:
This message comes from the process that was started. All subsequent messages that contain this pid come from
the same process.
Debuggable Attribute
4/12/2018 • 2 minutes to read • Edit Online
To make debugging possible, Android supports the Java Debug Wire Protocol (JDWP ). This is a technology that
allows tools such as ADB to communicate with a JVM. While JDWP is important during development, it should be
disabled prior to the applicaiton being published.
JDWP can be the value of the android:debuggable attribute in an Android application. Xamarin.Android provides
the following ways to set this attribute:
1. Created a AndroidManifext.xml file, and setting the android:debuggable attribute there.
2. Including the ApplicationAttribute in a .CS file like so : [assembly: Application(Debuggable=false)] .
If both the AndroidManifest.xml and the ApplicationAttribute are present, the contents of AndroidManifest.xml
take priority over what is specified by the ApplicationAttribute .
If neither the nor the ApplicationAttribute is present, then the default value of the
AndroidManifest.xml
android:debuggable attribute depends on whether or not debug symbols are generated. If debug symbols are
present, then Xamarin.Android will set the android:debuggable attribute to true .
Note that the value of the android:debuggable attribute does NOT necessarily depend on the build configuration.
It is possible for release builds to have the android:debuggable attribute set to true.
Related Links
Debuggable apps in the Android market
Xamarin.Android Environment
4/12/2018 • 4 minutes to read • Edit Online
Execution Environment
The execution environment is the set of environment variables and Android system properties that influence
program execution. Android system properties can be set with the adb shell setprop command, while
environment variables can be set by setting the debug.mono.env system property:
Android system properties are set for all processes on the target device.
Starting with Xamarin.Android 4.6, both system properties and environment variables may be set or overridden
on a per-app basis by adding an environment file to the project. An environment file is a Unix-formatted plain-text
file with a Build action of AndroidEnvironment . The environment file contains lines with the format key=value.
Comments are lines which start with # . Blank lines are ignored.
If key starts with an uppercase letter, then key is treated as an environment variable and setenv(3) is used to set
the environment variable to the specified value during process startup.
If key starts with a lowercase letter, then key is treated as an Android system property and value is the default
value: Android system properties which control Xamarin.Android execution behavior are looked up first from the
Android system property store, and if no value is present then the value specified in the environment file is used.
This is to permit adb shell setprop to be used to override values which come from the environment file for
diagnostic purposes.
The assembly-qualified type which must inherit from HttpMessageHandler and is constructed from the
HttpClient() default constructor.
In Xamarin.Android 6.1, this environment variable is not set by default, and HttpClientHandler will be used.
Alternatively, the value Xamarin.Android.Net.AndroidClientHandler may be specified to use java.net.URLConnection
for network access, which may permit use of TLS 1.2 when Android supports it.
Added in Xamarin.Android 6.1.
debug.mono.debug
The value of the debug.mono.debug system property is an integer. If 1 , then behave "as if" the process were
started with mono --debug . This generally shows file and line information in stack traces, etc., without requiring
that the app be started from a debugger.
debug.mono.env
The value of the debug.mono.debug system property is an integer. If 1 , then GC information should be logged.
This is equivalent to having the debug.mono.log system property contain gc .
debug.mono.log
Controls which additional information Xamarin.Android will log to adb logcat . It is a comma-separated string ( ,
), containing one of the following values:
all: Print out all messages. This is seldom a good idea, as it includes lref messages.
assembly : Print out .apk and assembly parsing messages.
gc : Print out GC -related messages.
gref : Print out JNI Global Reference messages.
lref : Print out JNI Local Reference messages.
Note: This will really spam adb logcat .
In Xamarin.Android 5.1, this will also create a .__override__/lrefs.txt file, which can get gigantic.
Avoid.
timing : Print out some method timing information. This will also create the files .__override__/methods.txt
and .__override__/counters.txt .
debug.mono.max_grefc
The value of the debug.mono.max_grefc system property is an integer. It's value overrides the default detected
maximum GREF count for the target device.
Please note: This is only usable with adb shell setprop debug.mono.max_grefc as the value will not be available in
time with an environment.txt file.
debug.mono.profile
The debug.mono.profile system property enables the profiler. It is equivalent to, and uses the same values as, the
mono --profile option. (See the mono(1) man page for more information.)
debug.mono.runtime_args
The debug.mono.runtime_args system property contains additional options that should be parsed by mono.
debug.mono.trace
The debug.mono.trace system property enables tracing. It is equivalent to, and uses the same values as, the
mono --trace option. (See the mono(1) man page for more information.)
In general, do not use. Use of tracing will spam adb logcat output, severaly slow down program behavior, and
alter program behavior (up to and including adding additional error conditions).
Sometimes, however, it allows some additional investigation to be performed...
debug.mono.wref
The debug.mono.wref system property allows overriding the default detected JNI Weak Reference mechanism.
There are two supported values:
jni : Use JNI weak references, as created by JNIEnv::NewWeakGlobalRef() and destroyed by
JNIEnv::DeleteWeakGlobalREf() .
java : Use JNI Global references which reference java.lang.WeakReference instances.
java is used, by default, up through API-7 and on API-19 (Kit Kat) with ART enabled. (API-8 added jni
references, and ART broke jni references.)
This system property is useful for testing and certain forms of investigation. In general, it should not be changed.
XA_HTTP_CLIENT_HANDLER_TYPE
First introduced in Xamarin.Android 6.1, this environment variable declares the default HttpMessageHandler
implementation that will be used by the HttpClient . By default this variable is not set, and Xamarin.Android will
use the HttpClientHandler .
XA_HTTP_CLIENT_HANDLER_TYPE=Xamarin.Android.Net.AndroidClientHandler
NOTE
The underlying Android device must support TLS 1.2. Android 5.0 and later support TLS 1.2
Example
## Comments are lines which start with '#'
## Blank lines are ignored.
Related Links
Transport Layer Security
GDB
7/25/2018 • 3 minutes to read • Edit Online
Overview
Xamarin.Android 4.10 introduced partial support for using gdb by using the the _Gdb MSBuild target.
NOTE
gdb support requires that the Android NDK be installed.
First, install the the app. This can be done via the IDE, or via the command line:
Secondly, run the _Gdb target. At the end of execution, a gdb command line will be printed:
The _Gdb target will launch an arbitrary launcher Activity declared within your AndroidManifest.xml file. To
explicitly specify which Activity to run, use the RunActivity MSBuild property. Starting Services and other
Android constructs is not supported at this time.
The _Gdbtarget will create a gdb-symbols directory and copy the contents of your target's /system/lib and
$APPDIR/lib directories there.
NOTE
The contents of the gdb-symbols directory are tied to the Android target you deployed to, and will not be automatically
replaced should you change the target. (Consider this a bug.) If you change Android target devices, you will need to manually
delete this directory.
Finally, copy the generated gdb command and execute it in your shell:
$ "/opt/android/ndk/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi-gdb"
-x "/Users/jon/Development/Projects/Scratch.HelloXamarin20//gdb-symbols/gdb.env"
GNU gdb (GDB) 7.3.1-gg2
...
(gdb) bt
#0 0x40082e84 in nanosleep () from /Users/jon/Development/Projects/Scratch.HelloXamarin20/gdb-symbols/libc.so
#1 0x4008ffe6 in sleep () from /Users/jon/Development/Projects/Scratch.HelloXamarin20/gdb-symbols/libc.so
#2 0x74e46240 in ?? ()
#3 0x74e46240 in ?? ()
(gdb) c
Once the system property has been set, execute the _Gdb target and the printed gdb command, as with the
Debug Builds with Fast Deployment configuration:
Release Builds
gdb support requires three things:
1. The INTERNET permission.
2. App Debugging enabled.
3. An accessible gdbserver .
The INTERNET permission is enabled by default in Debug apps. If it is not already present in your application, you
may add it either by editing Properties/AndroidManifest.xml or by editing the Project Properties.
App debugging can be enabled by either setting the ApplicationAttribute.Debugging custom attribute property to
true , or by editing Properties/AndroidManifest.xml and setting the //application/@android:debuggable
attribute to true :
An accessible gdbserver may be provided by following the Debug Builds without Fast Deployment section.
One wrinkle: The _Gdb MSBuild target will kill any previously running app instances. This will not work on pre-
Android v4.0 targets.
Troubleshooting
mono_pmip doesn't work
The mono_pmip function (useful for obtaining managed stack frames) is exported from libmonosgen-2.0.so , which
the _Gdb target does not currently pull down. (This will be fixed in a future release.)
To enable calling functions located in libmonosgen-2.0.so , copy it from the target device into the gdb-symbols
directory:
$ "/path/to/arm-linux-androideabi-gdb" -x "Project/gdb-symbols/gdb.env"
GNU gdb (GDB) 7.3.1-gg2
Copyright (C) 2011 Free Software Foundation, Inc.
...
(gdb) bt
No stack.
This is usually a sign that the contents of the gdb-symbols directory are not synchronized with your Android target.
(Did you change your Android target?)
Please delete the gdb-symbols directory and try again.
Linking on Android
4/12/2018 • 5 minutes to read • Edit Online
Xamarin.Android applications use a linker to reduce the size of the application. The linker employes static analysis
of your application to determine which assemblies are actually used, which types are actually used, and which
members are actually used. The linker then behaves like a garbage collector, continually looking for the
assemblies, types, and members that are referenced until the entire closure of referenced assemblies, types, and
members is found. Then everything outside of this closure is discarded.
For example, the Hello, Android sample:
Linking results in a package that is 30% the size of the original (unlinked) package in 1.2.0, and 18% of the
unlinked package in 4.0.1.
Control
Linking is based on static analysis. Consequently, anything that depends upon the runtime environment won't be
detected:
Linker Behavior
The primary mechanism for controlling the linker is the Linker Behavior (Linking in Visual Studio) drop-down
within the Project Options dialog box. There are three options:
1. Don't Link (None in Visual Studio)
2. Link SDK Assemblies (Sdk Assemblies Only)
3. Link All Assemblies (Sdk and User Assemblies)
The Don't Link option turns off the linker; the above "Release without Linking" application size example used this
behavior. This is useful for troubleshooting runtime failures, to see if the linker is responsible. This setting is not
usually recommended for production builds.
The Link SDK Assemblies option only links assemblies that come with Xamarin.Android. All other assemblies
(such as your code) are not linked.
The Link All Assemblies option links all assemblies, which means your code may also be removed if there are no
static references.
The above example will work with the Don't Link and Link SDK Assemblies options, and will fail with the Link All
Assemblies behavior, generating the following error:
Preserving Code
The linker will sometimes remove code that you want to preserve. For example:
You might have code that you call dynamically via System.Reflection.MemberInfo.Invoke .
If you instantiate types dynamically, you may want to preserve the default constructor of your types.
If you use XML serialization, you may want to preserve the properties of your types.
In these cases, you can use the Android.Runtime.Preserve attribute. Every member that is not statically linked by
the application is subject to be removed, so this attribute can be used to mark members that are not statically
referenced but are still needed by your application. You can apply this attribute to every member of a type, or to
the type itself.
In the following example, this attribute is used to preserve the constructor of the Example class:
If you want to preserve the entire type, you can use the following attribute syntax:
[Android.Runtime.Preserve (AllMembers = true)]
For example, in the following code fragment the entire Example class is preserved for XML serialization:
Sometimes you want to preserve certain members, but only if the containing type was preserved. In those cases,
use the following attribute syntax:
If you do not want to take a dependency on the Xamarin libraries – for example, you are building a cross platform
portable class library (PCL ) – you can still use the Android.Runtime.Preserve attribute. To do this, declare a
PreserveAttribute class within the Android.Runtime namespace like this:
namespace Android.Runtime
{
public sealed class PreserveAttribute : System.Attribute
{
public bool AllMembers;
public bool Conditional;
}
}
In the above examples, the Preserve attribute is declared in the Android.Runtime namespace; however, you can
use the Preserve attribute in any namespace because the linker looks up this attribute by type name.
falseflag
If the [Preserve] attribute can't be used, it is often useful to provide a block of code so that the linker believes that
the type is used, while preventing the block of code from being executed at runtime. To make use of this technique,
we could do:
// ...
}
linkskip
It is possible to specify that a set of user-provided assemblies should not be linked at all, while allowing other user
assemblies to be skipped with the Link SDK Assemblies behavior by using the AndroidLinkSkip MSBuild property:
<PropertyGroup>
<AndroidLinkSkip>Assembly1;Assembly2</AndroidLinkSkip>
</PropertyGroup>
LinkDescription
The @(LinkDescription) Build action may be used on files which can contain a Custom linker configuration file.
file. Custom linker configuration files may be required to preserve internal or private members that need to be
preserved.
Custom Attributes
When an assembly is linked, the following custom attribute types will be removed from all members:
System.ObsoleteAttribute
System.MonoDocumentationNoteAttribute
System.MonoExtensionAttribute
System.MonoInternalNoteAttribute
System.MonoLimitationAttribute
System.MonoNotSupportedAttribute
System.MonoTODOAttribute
System.Xml.MonoFIXAttribute
When an assembly is linked, the following custom attribute types will be removed from all members in Release
builds:
System.Diagnostics.DebuggableAttribute
System.Diagnostics.DebuggerBrowsableAttribute
System.Diagnostics.DebuggerDisplayAttribute
System.Diagnostics.DebuggerHiddenAttribute
System.Diagnostics.DebuggerNonUserCodeAttribute
System.Diagnostics.DebuggerStepperBoundaryAttribute
System.Diagnostics.DebuggerStepThroughAttribute
System.Diagnostics.DebuggerTypeProxyAttribute
System.Diagnostics.DebuggerVisualizerAttribute
Related Links
Custom Linker Configuration
Linking on iOS
Multi-Core Devices & Xamarin.Android
4/12/2018 • 9 minutes to read • Edit Online
Android can run on several different computer architectures. This document discusses the different CPU
architectures that may be employed for a Xamarin.Android application. This document will also explain how
Android applications are packaged to support different CPU architectures. The Application Binary Interface (ABI )
will be introduced, and guidance will be provided regarding which ABIs to use in a Xamarin.Android application.
Overview
Android allows for the creation of "fat binaries," a single .apk file that contains machine code that will support
multiple, different CPU architectures. This is accomplished by associating each piece of machine code with an
Application Binary Interface. The ABI is used to control which machine code will run on a given hardware device.
For example, for an Android application to run on an x86 device, it is necessary to include x86 ABI support when
compiling the application.
Specifically, each Android application will support at least one embedded -application binary interface (EABI). EABI
are conventions specific to embedded software programs. A typical EABI will describe things such as:
The CPU instruction set.
The endianness of memory stores and loads at run time.
The binary format of object files and program libraries, as well as which type of content is allowed or
supported in these files and libraries.
The various conventions used to pass data between application code and the system (for example: how
registers and/or the stack are used when functions are called, alignment constraints, etc.)
Alignment and size constraints for enum types, structures, fields, and arrays.
The list of function symbols available to your machine code at run time, generally from a very specific
selected set of libraries.
armeabi and Thread Safety
The Application Binary Interface will be discussed in detail below, but it is important to remember that the
armeabi runtime used by Xamarin.Android is not thread safe. If an application that has armeabi support is
deployed to an armeabi-v7a device, many strange and unexplainable exceptions will occur.
Due to a bug in Android 4.0.0, 4.0.1, 4.0.2, and 4.0.3, the native libraries will be picked up from the armeabi
directory even though there is an armeabi-v7a directory present and the device is an armeabi-v7a device.
NOTE
Xamarin.Android will ensure that .so are added to the APK in the correct order. This bug should not be an issue for users
of Xamarin.Android.
ABI Descriptions
Each ABI supported by Android is identified by a unique name.
armeabi
This is the name of an EABI for ARM -based CPUs that support at least the ARMv5TE instruction set. Android
follows the little-endian ARM GNU/Linux ABI. This ABI does not support hardware-assisted floating-point
computations. All FP operations are performed by software helper functions that come from the compiler's
libgcc.a static library. SMP devices are not supported by armeabi .
Note: Xamarin.Android's armeabi code is not thread safe and should not be used on multi-CPU armeabi-v7a
devices (described below ). Using aremabi code on a single-core armeabi-v7a device is safe.
armeabi-v7a
This is another ARM -based CPU instruction set that extends the armeabi EABI described above. The armeabi-v7a
EABI has support for hardware floating-point operations and multiple CPU (SMP ) devices. An application that
uses the armeabi-v7a EABI can expect substantial performance improvements over an application that uses
armeabi .
META -INF – This directory (if present) is used to store signing information, package, and extension
configuration data.
res – This directory holds the resources that were not compiled into resources.arsc .
NOTE
The file libmonodroid.so is the native library required by all Xamarin.Android applications.
lib/armeabi/libone.so
lib/armeabi/libtwo.so
lib/armeabi-v7a/libtwo.so
In other words, no libone.so is installed. This will cause problems, as libone.so is not present for the application
to load at run time. This behavior, while unexpected, has been logged as a bug and reclassified as "working as
intended."
Consequently, when targeting Android versions prior to 4.0, it is necessary to provide all native libraries for each
ABI that the application will support, that is, the .apk should contain:
lib/armeabi/libone.so
lib/armeabi/libtwo.so
lib/armeabi-v7a/libone.so
lib/armeabi-v7a/libtwo.so
lib/armeabi/libone.so
lib/armeabi/libtwo.so
lib/armeabi-v7a/libtwo.so
$APP/lib/libone.so
$APP/lib/libtwo.so
Unfortunately, this behavior is order dependent, as described in the following document - Issue 24321: Galaxy
Nexus 4.0.2 uses armeabi native code when both armeabi and armeabi-v7a is included in apk.
The native libraries are processed "in order" (as listed by, for example, unzip), and the first match is extracted. Since
the .apk contains armeabi and armeabi-v7a versions of libtwo.so , and the armeabi is listed first, it's the
armeabi version that is extracted, not the armeabi-v7a version:
$APP/lib/libone.so # armeabi
$APP/lib/libtwo.so # armeabi, NOT armeabi-v7a!
Furthermore, even if both armeabi and armeabi-v7a ABIs are specified (as described below in the section
Declaring Supported ABIs), Xamarin.Android will create the following element in the . csproj :
<AndroidSupportedAbis>armeabi,armeabi-v7a</AndroidSupportedAbis>
Consequently, the armeabi libmonodroid.so will be found first within the .apk , and the armeabi
libmonodroid.so will be the one that is extracted, even though the armeabi-v7a libmonodroid.so is present and
optimized for the target. This can also result in obscure run-time errors, as armeabi is not SMP safe.
I n st a l l i n g N a t i v e L i b r a r i e s: A n d r o i d 4 .0 .4 a n d l a t e r
Android 4.0.4 changes the extraction logic: it will enumerate all native libraries, read the file's basename, then
extract the primary ABI version (if present), or the secondary ABI (if present). This allows "merging" behavior; that
is, if we have an .apk with the following contents:
lib/armeabi/libone.so
lib/armeabi/libtwo.so
lib/armeabi-v7a/libtwo.so
Note that 64-bit runtimes are not required to run your app on 64-bit devices. For more information about
experimental features in Xamarin.Android 5.1, see Experimental Features.
Xamarin.Android does not currently provide support for mips .
Declaring Supported ABI's
By default, Xamarin.Android will default to armeabi-v7a for Release builds, and to armeabi-v7a and x86 for
Debug builds. Support for different ABIs can be set through the Project Options for a Xamarin.Android project. In
Visual Studio, this can be set in the Android Options page of project Properties, under the Advanced tab, as
shown in the following screenshot:
In Visual Studio for Mac, the supported architectures may be selected on the Android Build page of Project
Options, under the Advanced tab, as shown in the following screenshot:
There are some situations when it may be necessary to declare additional ABI support such as when:
Deploying the application to an x86 device.
Deploying the application to an armeabi-v7a device to ensure thread safety.
Summary
This document discussed the different CPU architectures that an Android application may run on. It introduced the
Application Binary Interface and how it is used by Android to support disparate CPU architectures. It then went on
to discuss how to specify ABI support in a Xamarin.Android application and highlighted the issues that arise when
using Xamarin.Android applications on an armeabi-v7a device that are intended only for armeabi .
Related Links
MIPS Architecture
ABI for the ARM Architecture (PDF )
Android NDK
Issue 9089:Nexus One - Won't load ANY native libraries from armeabi if there's at least one library at armeabi-
v7a
Issue 24321: Galaxy Nexus 4.0.2 uses armeabi native code when both armeabi and armeabi-v7a is included in
apk
Xamarin.Android Performance
4/12/2018 • 7 minutes to read • Edit Online
There are many techniques for increasing the performance of applications built with Xamarin.Android. Collectively
these techniques can greatly reduce the amount of work being performed by a CPU, and the amount of memory
consumed by an application. This article describes and discusses these techniques.
Performance Overview
Poor application performance presents itself in many ways. It can make an application seem unresponsive, can
cause slow scrolling, and can reduce battery life. However, optimizing performance involves more than just
implementing efficient code. The user's experience of application performance must also be considered. For
example, ensuring that operations execute without blocking the user from performing other activities can help to
improve the user's experience.
There are a number of techniques for increasing the performance, and perceived performance, of applications built
with Xamarin.Android. They include:
Optimize Layout Hierarchies
Optimize List Views
Remove Event Handlers in Activities
Limit the Lifespan of Services
Release Resources when Notified
Release Resources when the User Interface is Hidden
Optimize Image Resources
Dispose of Unused Image Resources
Avoid Floating-Point Arithmetic
Dismiss Dialogs
NOTE
Before reading this article you should first read Cross-Platform Performance, which discusses non-platform specific
techniques to improve the memory usage and performance of applications built using the Xamarin platform.
This layout is 3-levels deep, and is wasteful when inflated for each ListView row. However, it can be improved by
flattening the layout, as shown in the following code example:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="5dip">
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_marginRight="5dip"
android:src="@drawable/icon" />
<TextView
android:id="@+id/secondLine"
android:layout_width="fill_parent"
android:layout_height="25dip"
android:layout_toRightOf="@id/icon"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:singleLine="true"
android:ellipsize="marquee"
android:text="Lorem ipsum dolor sit amet." />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/icon"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_above="@id/secondLine"
android:layout_alignWithParentIfMissing="true"
android:gravity="center_vertical"
android:text="Mei tempor iuvaret ad." />
</RelativeLayout>
The previous 3-level hierarchy has been reduced to a 2-level hierarchy, and a single RelativeLayout has replaced
two LinearLayout instances. A significant performance increase will be gained when inflating the layout for each
ListView row.
As the user scrolls, the ListView calls the GetView override to request new views to display – if available it passes
an unused view in the convertView parameter. If this value is null then the code creates a new View instance,
otherwise the convertView properties can be reset and reused.
For more information, see Row View Re-Use in Populating a ListView with Data.
EventHandler<UpdatingEventArgs> service1UpdateHandler;
When the activity exits the running state, OnPause is called. In the OnPause implementation, remove the handlers
as follows:
App.Current.Service1.Updated -= service1UpdateHandler;
In addition, when the application process is cached, the following memory level notifications may be received by
the OnTrimMemory callback:
TrimMemoryBackground – release resources that can be quickly and efficiently rebuilt if the user returns to the
app.
TrimMemoryModerate – releasing resources can help the system keep other processes cached for better overall
performance.
TrimMemoryComplete – the application process will soon be terminated if more memory isn't soon recovered.
For more information about releasing disposable resources, see Release IDisposable Resources.
NOTE
Even for integer arithmetic, some CPUs lack hardware divide capabilities. Therefore, integer division and modulus operations
are often performed in software.
Dismiss Dialogs
When using the ProgressDialog class (or any dialog or alert), instead of calling the Hide method when the
dialog's purpose is complete, call the Dismiss method. Otherwise, the dialog will still be alive and will leak the
activity by holding a reference to it.
Summary
This article described and discussed techniques for increasing the performance of applications built with
Xamarin.Android. Collectively these techniques can greatly reduce the amount of work being performed by a CPU,
and the amount of memory consumed by an application.
Related Links
Cross-Platform Performance
Profiling Android Apps
6/27/2018 • 3 minutes to read • Edit Online
Before deploying your app to an app store, it's important to identify and fix any performance bottlenecks, excessive
memory usage issues, or inefficient use of network resources. Two profiler tools are available to serve this
purpose:
Xamarin Profiler
Android Profiler in Android Studio
This guide introduces the Xamarin Profiler and provides detailed information for getting started with using the
Android Profiler.
Xamarin Profiler
The Xamarin Profiler is a standalone application that is integrated with Visual Studio and Visual Studio for Mac for
profiling Xamarin apps from within the IDE. For more information about using the Xamarin Profiler, see Xamarin
Profiler.
NOTE
You must be a Visual Studio Enterprise subscriber to unlock the Xamarin Profiler feature in either Visual Studio Enterprise on
Windows or Visual Studio for Mac.
5. In the Select APK File dialog, navigate to the APK that you built and copied earlier. Select the APK and
click OK:
6. Android Studio will load the APK and dissassembles classes.dex:
7. After the APK is loaded, Android Studio displays the following project screen for the APK. Right-click the
app name in the tree view on the left and select Open Module Settings:
8. Navigate to Project Settings > Modules, select the -Signed node of the app, then click <No SDK>:
9. In the Module SDK pull-down menu, select the Android SDK level that was used to build the app (in this
example, API level 26 was used to build XamagonXuzzle):
11. Select the deployment target for running/profiling the app and click OK. The deployment target can be a
physical device or a virtual device running in an emulator. In this example, a Nexus 5X device is used:
12. After the profiler starts, it will take a few seconds for it to connect to the deployment device and the app
process. While it is installing the APK, Android Profiler will report No connected devices and No
debuggable processes.
13. After several seconds, Android Profiler will complete APK installation and launch the APK, reporting the
device name and the name of the app process being profiled (in this example, LGE Nexus 5X and
com.companyname.XamagonXuzzle, respectively):
14. After the device and debuggable process are identified, Android Profiler begins profiling the app:
15. If you tap the RANDOMIZE button on XamagonXuzzle (which causes it to shift and randomize tiles), you
will see the CPU usage increase during the app's randomization interval:
After an application has been coded and tested, it is necessary to prepare a package for distribution. The first task
in preparing this package is to build the application for release, which mainly entails setting some application
attributes.
Use the following steps to build the app for release:
Specify the Application Icon – Each Xamarin.Android application should have an application icon
specified. Although not technically necessary, some markets, such as Google Play, require it.
Version the Application – This step involves initializing or updating the versioning information. This is
important for future application updates and to ensure that the users are aware of which version of the
application they have installed.
Shrink the APK – The size of the final APK can be substantially reduced by using the Xamarin.Android
linker on the managed code and ProGuard on the Java bytecode.
Protect the Application – Prevent users or attackers from debugging, tampering, or reverse engineering
the application by disabling debugging, obfuscating the managed code, adding anti-debug and anti-tamper,
and using native compilation.
Set Packaging Properties – Packaging properties control the creation of the Android application package
(APK). This step optimizes the APK, protects its assets, and modularizes the packaging as needed.
Compile – This step compiles the code and assets to verify that it builds in Release mode.
Archive for Publishing – This step builds the app and places it in an archive for signing and publishing.
Each of these steps is described below in more detail.
Visual Studio
Visual Studio for Mac
In Visual Studio 2015 and later, specify the application icon through the Android Manifest section of project
Properties, as shown in the following screenshot:
In these examples, @drawable/icon refers to an icon file that is located at Resources/drawable/icon.png (note
that the .png extension is not included in the resource name). This attribute can also be declared in the file
Properties\AssemblyInfo.cs, as shown in this sample snippet:
Normally, using Android.App is declared at the top of AssemblyInfo.cs (the namespace of the Application
attribute is Android.App ); however, you may need to add this using statement if it is not already present.
The Linking pull-down menu provides the following options for controlling the linker:
None – This turns off the linker; no linking will be performed.
SDK Assemblies Only – This will only link the assemblies that are required by Xamarin.Android. Other
assemblies will not be linked.
Sdk and User Assemblies – This will link all assemblies that are required by the application, and not just
the ones required by Xamarin.Android.
Linking can produce some unintended side effects, so it is important that an application be re-tested in Release
mode on a physical device.
ProGuard
ProGuard is an Android SDK tool that links and obfuscates Java code. ProGuard is normally used to create
smaller applications by reducing the footprint of large included libraries (such as Google Play Services) in your
APK. ProGuard removes unused Java bytecode, which makes the resulting app smaller. For example, using
ProGuard on small Xamarin.Android apps usually achieves about a 24% reduction in size – using ProGuard on
larger apps with multiple library dependencies typically achieves an even greater size reduction.
ProGuard is not an alternative to the Xamarin.Android linker. The Xamarin.Android linker links managed code,
while ProGuard links Java bytecode. The build process first uses the Xamarin.Android linker to optimize the
managed (C#) code in the app, and then it later uses ProGuard (if enabled) to optimize the APK at the Java
bytecode level.
When Enable ProGuard is checked, Xamarin.Android runs the ProGuard tool on the resulting APK. A ProGuard
configuration file is generated and used by ProGuard at build time. Xamarin.Android also supports custom
ProguardConfiguration build actions. You can add a custom ProGuard configuration file to your project, right-click
it, and select it as a build action as shown in this example:
Visual Studio
Visual Studio for Mac
ProGuard is disabled by default. The Enable ProGuard option is available only when the project is set to Release
mode. All ProGuard build actions are ignored unless Enable ProGuard is checked. The Xamarin.Android
ProGuard configuration does not obfuscate the APK, and it is not possible to enable obfuscation, even with
custom configuration files. If you wish to use obfuscation, please see Application Protection with Dotfuscator.
For more detailed information about using the ProGuard tool, see ProGuard.
Protect the Application
Disable Debugging
During development of an Android application, debugging is performed with the use of the Java Debug Wire
Protocol (JDWP ). This is a technology that allows tools such as adb to communicate with a JVM for the purposes
of debugging. JDWP is turned on by default for Debug builds of a Xamarin.Android application. While JDWP is
important during development, it can pose a security issue for released applications.
IMPORTANT
Always disable the debug state in a released application as it is possible (via JDWP) to gain full access to the Java process
and execute arbitrary code in the context of the application if this debug state is not disabled.
The Android Manifest contains the android:debuggable attribute, which controls whether or not the application
may be debugged. It is considered a good practice to set the android:debuggable attribute to false . The simplest
way to do this is by adding a conditional compile statement in AssemblyInfo.cs:
#if DEBUG
[assembly: Application(Debuggable=true)]
#else
[assembly: Application(Debuggable=false)]
#endif
Note that Debug builds automatically set some permissions to make debug easier (such as Internet and
ReadExternalStorage). Release builds, however, use only the permissions that you explicitly configure. If you find
that switching to the Release build causes your app to lose a permission that was available in the Debug build,
verify that you have explicitly enabled this permission in the Required permissions list as described in
Permissions.
Application Protection with Dotfuscator
Visual Studio
Visual Studio for Mac
Even with debugging disabled, it is still possible for attackers to re-package an application, adding or removing
configuration options or permissions. This allows them to reverse-engineer, debug, or tamper with the application.
Dotfuscator Community Edition (CE ) can be used to obfuscate managed code and inject runtime security state
detection code into a Xamarin.Android app at build time to detect and respond if the app is running on a rooted
device.
Dotfuscator CE is included with Visual Studio, however only Visual Studio 2015 Update 3 (and higher) has the
correct version to work with Xamarin.Android. To use Dotfuscator, click Tools > PreEmptive Protection -
Dotfuscator.
To configure Dotfuscator CE, please see Using Dotfuscator Community Edition with Xamarin. Once it is
configured, Dotfuscator CE will automatically protect each build that is created.
Bundle Assemblies into Native Code
When this option is enabled, assemblies are bundled into a native shared library. This option keeps the code safe;
it protects managed assemblies by embedding them in native binaries.
This option requires an Enterprise license and is only available when Use Fast Deployment is disabled. Bundle
assemblies into native code is disabled by default.
Note that the Bundle into Native Code option does not mean that the assemblies are compiled into native code.
It is not possible to use AOT Compilation to compile assemblies into native code (currently only an experimental
feature, and not for production use).
AOT Compilation
The AOT Compilation option (on the Packaging Properties page) enables Ahead-of-Time (AOT) compilation of
assemblies. When this option is enabled, Just In Time (JIT) startup overhead is minimized by precompiling
assemblies before runtime. The resulting native code is included in the APK along with the uncompiled
assemblies. This results in shorter application startup time, but at the expense of slightly larger APK sizes.
The AOT Compilation option requires an Enterprise license or higher. AOT compilation is available only when
the project is configured for Release mode, and it is disabled by default. For more information about AOT
Compilation, see AOT.
LLVM Optimizing Compiler
The LLVM Optimizing Compiler will create smaller and faster compiled code and convert AOT-compiled
assemblies into native code, but at the expense of slower build times. The LLVM compiler is disabled by default. To
use the LLVM compiler, the AOT Compilation option must first be enabled (on the Packaging Properties page).
NOTE
The LLVM Optimizing Compiler option requires a Business license.
Many of these properties, such as Use Shared Runtime, and Use Fast Deployment are intended for Debug
mode. However, when the application is configured for Release mode, there are other settings that determine how
the app is optimized for size and execution speed, how it is protected from tampering, and how it can be packaged
to support different architectures and size restrictions.
Specify Supported Architectures
When preparing a Xamarin.Android app for release, it is necessary to specify the CPU architectures that are
supported. A single APK can contain machine code to support multiple, different architectures. See CPU
Architectures for details about supporting multiple CPU architectures.
Generate One Package (.APK ) per Selected ABI
When this option is enabled, one APK will be created for each of the supported ABI's (selected on the Advanced
tab, as described in CPU Architectures) rather than a single, large APK for all supported ABI's. This option is
available only when the project is configured for Release mode, and it is disabled by default.
Multi-Dex
When the Enable Multi-Dex option is enabled, Android SDK tools are used to bypass the 65K method limit of
the .dex file format. The 65K method limitation is based on the number of Java methods that an app references
(including those in any libraries that the app depends on) – it is not based on the number of methods that are
written in the source code. If an application only defines a few methods but uses many (or large libraries), it is
possible that the 65K limit will be exceeded.
It is possible that an app is not using every method in every library that is referenced; therefore, it is possible that
a tool such as ProGuard (see above) can remove the unused methods from code. The best practice is to enable
Enable Multi-Dex only if absolutely necessary, i.e.the app still references more than 65K Java methods even
after using ProGuard.
For more information about Multi-Dex, see Configure Apps with Over 64K Methods.
Compile
Visual Studio
Visual Studio for Mac
After all of the above steps are completed, the app is ready for compilation. Select Build > Rebuild Solution to
verify that it builds successfully in Release mode. Note that this step does not yet produce an APK.
Signing the App Package discusses packaging and signing in more detail.
Another way to create an archive is to right-click the Solution in the Solution Explorer and select Archive All...,
which builds the solution and archives all Xamarin projects that can generate an archive:
Both Archive and Archive All automatically launch the Archive Manager. To launch the Archive Manager
directly, click the Tools > Archive Manager... menu item:
The solution's archives at any time by right clicking the Solution node and selecting View Archives:
The Archive Manager
The Archive Manager is comprised of a Solution List pane, an Archives List, and a Details Panel:
The Solution List displays all solutions having at least one archived project. The Solution List includes the
following sections:
Current Solution – Displays the current solution. Note that this area may be empty if the current solution
does not have an existing archive.
All Archives – Displays all solutions that have an archive.
Search text box (at the top) – Filters the solutions listed in the All Archives list according to the search string
entered in the text box.
The Archives List displays the list of all archives for the selected solution. The Archives List includes the
following sections:
Selected solution name – Displays the name of the solution selected in the Solution List. All information
shown in the Archives List refers to this selected solution.
Platforms Filter – This field makes it possible to filter archives by platform type (such as iOS or Android).
Archive Items – List of archives for the selected solution. Each item in this list includes the project name,
creation date, and platform. It can also show additional information such as the progress when an item is being
archived or published.
The Details Panel displays additional information about each archive. It also allows the user to start the
Distribution workflow or open the folder where the distribution has been created. The Build Comments section
makes it possible to include build comments in the archive.
Distribution
When an archived version of the application is ready to publish, select the archive in the Archive Manager and
click the Distribute... button:
The Distribution Channel dialog shows information about the app, an indication of distribution workflow
progress, and a choice of distribution channels. On the first run, two choices are presented:
Xamarin.Android ProGuard is a Java class file shrinker, optimizer, and pre-verifier. It detects and removes unused
code, analyzes and optimizes bytecode. This guide explains how ProGuard works, how to enable it in your project,
and how to configure it. It also provides several examples of ProGuard configurations.
Overview
ProGuard detects and removes unused classes, fields, methods, and attributes from your packaged application. It
can even do the same for referenced libraries (this can help you avoid the 64k reference limit). The ProGuard tool
from the Android SDK will also optimize bytecode and remove unused code instructions. ProGuard reads input
jars and then shrinks, optimizes, and pre-verifies them; it writes the results to one or more output jars.
ProGuard processes input APK's using the following steps:
1. Shrinking step – ProGuard recursively determines which classes and class members are used. All other
classes and class members are discarded.
2. Optimization step – ProGuard further optimizes the code. Among other optimizations, classes and
methods that are not entry points can be made private, static, or final, unused parameters can be removed,
and some methods may be inlined.
3. Obfuscation step – In native Android development, ProGuard renames classes and class members that
are not entry points. Retaining entry points ensures that they can still be accessed by their original names.
However, this step is not supported by Xamarin.Android because the app is compiled down to Intermediate
Language (IL ).
4. Preverification step – Performs checks on Java bytecodes ahead of runtime and annotates class files for
the benefit of the Java VM. This is the only step that doesn't have to know the entry points.
Each of these steps is optional. As will be explained in the next section, Xamarin.Android ProGuard uses only a
subset of these steps.
ProGuard in Xamarin.Android
The Xamarin.Android ProGuard configuration does not obfuscate the APK. In fact, is not possible to enable
obfuscation through ProGuard (even through the use of custom configuration files). Thus, Xamarin.Android's
ProGuard performs only the shrinking and optimization steps:
One important item to know in advance before using ProGuard is how it works within the Xamarin.Android build
process. This process uses two separate steps:
1. Xamarin Android Linker
2. ProGuard
Each of these steps is described next.
Linker Step
The Xamarin.Android linker employs static analysis of your application to determine the following:
Which assemblies are actually used.
Which types are actually used.
Which members are actually used.
The linker will always run before the ProGuard step. Because of this, the linker can strip an
assembly/type/member that you might expect ProGuard to run on. (For more information about linking in
Xamarin.Android, see Linking on Android.)
ProGuard Step
After the linker step completes successfully, ProGuard is run to remove unused Java bytecode. This is the step that
optimizes the APK.
Using ProGuard
To use ProGuard in your app project, you must first enable ProGuard. Next, you can either let the Xamarin.Android
build process use a default ProGuard configuration file, or you can create your own custom configuration file for
ProGuard to use.
Enabling ProGuard
Use the following steps to enable ProGuard in your app project:
1. Ensure that your project is set to the Release configuration (this is important because the linker must run in
order for ProGuard to run):
2. Enable ProGuard by checking the Enable ProGuard option under the Packaging tab of Properties >
Android Options:
For most Xamarin.Android apps, the default ProGuard configuration file supplied by Xamarin.Android will be
sufficient to remove all (and only) unused code. To view the default ProGuard configuration, open the file at
obj\Release\proguard\proguard_xamarin.cfg. The next section describes how to create a customized
ProGuard configuration file.
Customizing ProGuard
Optionally, you can add a custom ProGuard Configuration file to exert more control over the ProGuard tooling.
For example, you may want to explicitly tell ProGuard which classes to keep. To do this, create a new .cfg file and
apply the ProGuardConfiguration build action in the Properties pane of the Solution Explorer:
Keep in mind that this configuration file does not replace the Xamarin.Android proguard_xamarin.cfg file since
both are used by ProGuard.
The following example illustrates a typical ProGuard configuration file:
-dontobfuscate
There might be cases where ProGuard is unable to properly analyze your application; it could potentially remove
code that your application actually needs. If this happens, you can add a -keep line to your custom ProGuard
configuration file:
-dontpreverify
-repackageclasses ''
-allowaccessmodification
-optimizations !code/simplification/arithmetic
-injars bin/classes
-injars libs
-outjars bin/classes-processed.jar
-libraryjars /usr/local/java/android-sdk/platforms/android-9/android.jar
-dontpreverify
-repackageclasses ''
-allowaccessmodification
-optimizations !code/simplification/arithmetic
-keepattributes *Annotation*
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
The following listing provides an example of the default parameters that are generated after you a create a new
project using File > New Project:
ProGuardJarPath = C:\Android\android-sdk\tools\proguard\lib\proguard.jar
AndroidSdkDirectory = C:\Android\android-sdk\
JavaToolPath = C:\Program Files (x86)\Java\jdk1.8.0_92\\bin
ProGuardToolPath = C:\Android\android-sdk\tools\proguard\
JavaPlatformJarPath = C:\Android\android-sdk\platforms\android-25\android.jar
ClassesOutputDirectory = obj\Release\android\bin\classes
AcwMapFile = obj\Release\acw-map.txt
ProGuardCommonXamarinConfiguration = obj\Release\proguard\proguard_xamarin.cfg
ProGuardGeneratedReferenceConfiguration = obj\Release\proguard\proguard_project_references.cfg
ProGuardGeneratedApplicationConfiguration = obj\Release\proguard\proguard_project_primary.cfg
ProGuardConfigurationFiles
{sdk.dir}tools\proguard\proguard-android.txt;
{intermediate.common.xamarin};
{intermediate.references};
{intermediate.application};
;
The next example illustrates a typical ProGuard command that is run from the IDE:
Troubleshooting
File Issues
The following error message may be displayed when ProGuard reads its configuration file:
This issue typically happens on Windows because the .cfg file has the wrong encoding. ProGuard cannot handle
byte order mark (BOM ) which may be present in text files. If a BOM is present, then ProGuard will exit with the
above error.
Visual Studio
Visual Studio for Mac
To prevent this problem, edit the custom configuration file from a text editor that will allow the file to be saved
without a BOM. To solve this problem, ensure that your text editor has its encoding set to UTF-8 . For example, the
text editor Notepad++ can save files without the BOM by selecting the Encoding > Encode in UTF-8 Without
BOM when saving the file.
Other Issues
The ProGuard Troubleshooting page discusses common issues you may encounter (and solutions) when using
ProGuard.
Summary
This guide explained how ProGuard works in Xamarin.Android, how to enable it in your app project, and how to
configure it. It provided example ProGuard configurations, and it described solutions to common problems. For
more information about the ProGuard tool and Android, see Shrink Your Code and Resources.
Related Links
Preparing an Application for Release
Signing the Android Application Package
7/3/2018 • 4 minutes to read • Edit Online
In Preparing an App for Release the Archive Manager was used to build the app and place it in an archive for
signing and publishing. This section explains how to create an Android signing identity, create a new signing
certificate for Android applications, and publish the archived app ad hoc to disk. The resulting APK can be
sideloaded into Android devices without going through an app store.
Visual Studio
Visual Studio for Mac
In Archive for Publishing, the Distribution Channel dialog presented two choices for distribution. Select Ad-
Hoc:
The following example illustrates the kind of information that must be provided. Click Create to create the new
certificate:
The resulting keystore resides in the following location:
C:\Users\USERNAME\AppData\Local\Xamarin\Mono for Android\Keystore\ALIAS\ALIAS.keystore
For example, using chimp as the alias, the above steps would create a new signing key in the following location:
C:\Users\USERNAME\AppData\Local\Xamarin\Mono for Android\Keystore\chimp\chimp.keystore
NOTE
Be sure to back up the resulting keystore file and password in a safe place – it is not included in the Solution. If you lose
your keystore file (for example, because you moved to another computer or reinstalled Windows), you will be unable to sign
your app with the same certificate as previous versions.
For more information about the keystore, see Finding your Keystore's MD5 or SHA1 Signature.
Navigate to the desired location and click Save. If the key password is unknown, the Signing Password dialog
will appear to prompt for the password for the selected certificate:
After the signing process completes, click Open Distribution:
This causes Windows Explorer to open the folder containing the generated APK file. At this point, Visual Studio
has compiled the Xamarin.Android application into an APK that is ready for distribution. The following screenshot
displays an example of the ready-to-publish app, MyApp.MyApp.apk:
Next Steps
After the application package has been signed for release, it must be published. The following sections describe
several ways to publish an application.
Manually Signing the APK
4/12/2018 • 6 minutes to read • Edit Online
After the application has been built for release, the APK must be signed prior to distribution so that it can be run on
an Android device. This process is typically handled with the IDE, however there are some situations where it is
necessary to sign the APK manually, at the command line. The following steps are involved with signing an APK:
1. Create a Private Key – This step needs to be performed only once. A private key is necessary to digitally
sign the APK. After the private key has been prepared, this step can be skipped for future release builds.
2. Zipalign the APK – Zipalign is an optimization process that is performed on an application. It enables
Android to interact more efficiently with the APK at runtime. Xamarin.Android conducts a check at runtime,
and will not allow the application to run if the APK has not been zipaligned.
3. Sign the APK – This step involves using the apksigner utility from the Android SDK and signing the APK
with the private key that was created in the previous step. Applications that are developed with older
versions of the Android SDK build tools prior to v24.0.3 will use the jarsigner app from the JDK. Both of
these tools will be discussed in more detail below.
The order of the steps is important and is dependent on which tool used to sign the APK. When using apksigner, it
is important to first zipalign the application, and then to sign it with apksigner. If it is necessary to use jarsigner
to sign the APK, then it is important to first sign the APK and then run zipalign.
Prerequisites
This guide will focus on using apksigner from the Android SDK build tools, v24.0.3 or higher. It assumes that an
APK has already been built.
Applications that are built using an older version of the Android SDK Build Tools must use jarsigner as described
in Sign the APK with jarsigner below.
The first thing that keytool will ask for is the password for the keystore. Then it will ask for some information to
help with creating the key. The following snippet is an example of creating a new key called publishingdoc that will
be stored in the file xample.keystore :
$ keytool -genkeypair -v -keystore xample.keystore -alias publishingdoc -keyalg RSA -keysize 2048 -validity
10000
Enter keystore password:
Re-enter new password:
What is your first and last name?
[Unknown]: Ham Chimpanze
What is the name of your organizational unit?
[Unknown]: NASA
What is the name of your organization?
[Unknown]: NASA
What is the name of your City or Locality?
[Unknown]: Cape Canaveral
What is the name of your State or Province?
[Unknown]: Florida
What is the two-letter country code for this unit?
[Unknown]: US
Is CN=Ham Chimpanze, OU=NASA, O=NASA, L=Cape Canaveral, ST=Florida, C=US correct?
[no]: yes
Generating 2,048 bit RSA key pair and self-signed certificate (SHA1withRSA) with a validity of 10,000 days
for: CN=Ham Chimpanze, OU=NASA, O=NASA, L=Cape Canaveral, ST=Florida, C=US
Enter key password for <publishingdoc>
(RETURN if same as keystore password):
Re-enter new password:
[Storing xample.keystore]
To list the keys that are stored in a keystore, use the keytool with the – list option:
$ ls $ANDROID_HOME/build-tools/25.0.3/apksigner
/Users/tom/android-sdk-macosx/build-tools/25.0.3/apksigner*
The following snippet assumes that apksigner is accessible by the PATH environment variable. It will sign an APK
using the key alias publishingdoc that is contained in the file xample.keystore:
When this command is run, apksigner will ask for the password to the keystore if necessary.
See Google's documentation for more details on the use of apksigner.
NOTE
According to Google issue 62696222, apksigner is "missing" from the Android SDK. The workaround for this is to install the
Android SDK build tools v25.0.3 and use that version of apksigner.
WARNING
This section only applies if it is nececssary to sign the APK with the jarsigner utility. Developers are encouraged to use
apksigner to sign the APK.
This technique involves signing the APK file using the jarsigner command from the Java SDK. The jarsigner tool
is provided by the Java SDK.
The following shows how to sign an APK by using jarsigner and the key publishingdoc that is contained in a
keystore file named xample.keystore :
NOTE
When using jarsigner, it is important to sign the APK first, and then to use zipalign.
Related Links
Application Signing
Java JAR signing
jarsigner
keytool
zipalign
Build Tools 26.0.0 - where did apksigner go?
Finding your Keystore's Signature
4/12/2018 • 3 minutes to read • Edit Online
The MD5 or SHA1 signature of a Xamarin.Android app depends on the .keystore file that was used to sign the
APK. Typically, a debug build will use a different .keystore file than a release build.
When run, keytool.exe should output the following text. The MD5: and SHA1: labels identify the respective
signatures:
After a great application has been created, people will want to use it. This section covers the steps involved with
the public distribution of an application created with Xamarin.Android via channels such as e-mail, a private web
server, Google Play, or the Amazon App Store for Android.
Overview
The final step in the development of a Xamarin.Android application is to publish the application. Publishing is the
process of compiling a Xamarin.Android application so that it is ready for users to install on their devices, and it
involves two essential tasks:
Preparing for Publication – A release version of the application is created that can be deployed to
Android-powered devices (see Preparing an Application for Release for more information about release
preparation).
Distribution – The release version of an application is made available through one or more of the various
distribution channels.
The following diagram illustrates the steps involved with publishing a Xamarin.Android application:
As can be seen by the diagram above, the preparation is the same regardless of the distribution method that is
used. There are several ways that an Android application may be released to users:
Via a Website – A Xamarin.Android application can be made available for download on a website, from which
users may then install the application by clicking on a link.
By e-mail – It is possible for users to install a Xamarin.Android application from their e-mail. The application
will be installed when the attachment is opened with an Android-powered device.
Through a Market – There are several application marketplaces that exist for distribution, such as Google
Play or Amazon App Store for Android .
Using an established marketplace is the most common way to publish an application as it provides the broadest
market reach and the greatest control over distribution. However, publishing an application through a marketplace
requires additional effort.
Multiple channels can distribute a Xamarin.Android application simultaneously. For example, an application could
be published on Google Play, the Amazon App Store for Android, and also be downloaded from a web server.
The other two methods of distribution (downloading or e-mail) are most useful for a controlled subset of users,
such as an enterprise environment or an application that is only meant for a small or well-specified set of users.
Server and e-mail distribution are also simpler publishing models, requiring less preparation to publish an
application.
The Amazon Mobile App Distribution Program enables mobile app developers to distribute and sell their
applications on Amazon. Users can discover and shop for apps on their Android-powered devices by using the
Amazon App Store application. A screenshot of the Amazon App Store running on an Android device appears
below:
Google Play is arguably the most comprehensive and popular marketplace for Android applications. Google Play
allows users to discover, download, rate, and pay for applications by clicking a single icon either on their device or
on their computer. Google Play also provides tools to assist in the analysis of sales and market trends and to
control which devices and users may download an application. A screenshot of Google Play running on an
Android device appears below:
This section shows how to upload the application to a store such as Google Play, along with the appropriate
promotional materials. APK expansion files are explained, providing a conceptual overview of what they are and
how they work. Google Licensing services are also described. Finally, alternate means of distribution are
introduced, including the use of an HTTP web server, simple e-mail distribution, and the Amazon App Store for
Android.
Related Links
HelloWorldPublishing (sample)
Build Process
Linking
Obtaining A Google Maps API Key
Application Signing
Publishing on Google Play
Google Application Licensing
Android.Play.ExpansionLibrary
Mobile App Distribution Portal
Amazon Mobile App Distribution FAQ
Publishing to Google Play
7/17/2018 • 12 minutes to read • Edit Online
Although there are many app markets for distributing an application, Google Play is arguably the largest and
most visited store in the world for Android apps. Google Play provides a single platform for distributing,
advertising, selling, and analyzing the sales of an Android application.
This section will cover topics that are specific to Google Play, such as registering to become a publisher, gathering
assets to help Google Play promote and advertise your application, guidelines for rating your application on
Google Play, and using filters to restrict the deployment of an application to certain devices.
Requirements
To distribute an application through Google Play, a developer account must be created. This only needs to be
performed once, and does involve a one time fee of $25 USD.
All applications need to be signed with a cryptographic key that expires after October 22, 2033.
The maximum size for an APK published on Google Play is 100MB. If an application exceeds that size, Google
Play will allow extra assets to be delivered through APK Expansion Files. Android Expansion files permit the APK
to have 2 additional files, each of them up to 2GB in size. Google Play will host and distribute these files at no cost.
Expansion files will be discussed in another section.
Google Play is not globally available. Some locations may not be supported for the distribution of applications.
Becoming a Publisher
To publish applications on Google play, it is necessary to have a publisher account. To sign up for a publisher
account follow these steps:
1. Visit the Google Play Developer Console.
2. Enter basic information about your developer identity.
3. Read and accept the Developer Distribution Agreement for your locale.
4. Pay the $25 USD registration fee.
5. Confirm verification by e-mail.
6. After the account has been created, it is possible to publish applications using Google Play.
Google Play does not support all countries in the world. The most up to date lists of countries can be found in the
following links:
1. Supported Locations for Developer & Merchant Registration – This is a list of all countries where
developers may register as merchants and sell paid applications.
2. Supported Locations for distribution to Google Play users – This is a list of all countries where applications
may be distributed.
Preparing Promotional Assets
To effectively promote and advertise an application on Google Play, Google allows developers to submit
promotional assets such as screenshots, graphics, and video to be submitted. Google Play will then use those
assets to advertise and promote the application.
Launcher Icons
A launcher icon is a graphic that represents an application. Each launcher icon should be a 32-bit PNG with an
alpha channel for transparency. An application should have icons for all of the generalized screen densities as
outlined in the list below:
ldpi (120dpi) – 36 x 36 px
mdpi (160dpi) – 48 x 48 px
hdpi (240dpi) – 72 x 72 px
xhdpi (320dpi) – 96 x 96 px
Launcher icons are the first things that a user will see of applications on Google Play, so care should be taken to
make the launcher icons visually appealing and meaningful.
Tips for Launcher Icons:
1. Simple and uncluttered– Launcher icons should be kept simple and uncluttered. This means excluding
the name of the application from the icon. Simpler icons will be more memorable, and will be easier to
distinguish at the smaller sizes.
2. Icons should not be thin– Overly thin icons will not stand out well on all backgrounds.
3. Use the alpha channel– Icons should make use of the alpha channel, and should not be full-framed
images.
High Resolution Application Icons
Applications on Google Play require a high fidelity version of the application icon. It is only used by Google Play,
and does not replace the application launcher icon. The specifications for the high-resolution icon are:
1. 32-bit PNG with an alpha channel
2. 512 x 512 pixels
3. Maximum size of 1024KB
The Android Asset Studio is a helpful tool for creating suitable launcher icons and the high-resolution application
icon.
Screen Shots
Google play requires a minimum of two and a maximum of eight screen shots for an application. They will be
displayed on an application’s details page in Google Play.
The specs for screen shots are:
1. 24 bit PNG or JPG with no alpha channel
2. 320w x 480h or 480w x 800h or 480w x 854h. Landscaped images will be cropped.
Promotional Graphic
This is an optional image used by Google Play:
1. It is a 180w x 120h 24 bit PNG or JPG with no alpha channel.
2. No border in art.
Feature Graphic
Used by the featured section of Google Play. This graphic may be displayed alone without an application icon.
1. 1024w x 500h PNG or JPG with no alpha channel and no transparency.
2. All of the important content should be within a frame of 924x500. Pixels outside of this frame may be cropped
for stylistic purposes.
3. This graphic may be scaled down: use large text and keep graphics simple.
Video Link
This is a URL to a YouTube video showcasing the application. The video should be 30 seconds to 2 minutes in
length and showcase the best parts of your application.
Publishing to Google Play
Visual Studio
Visual Studio for Mac
Xamarin Android 7.0 introduces an integrated workflow for publishing apps to Google Play from Visual Studio. If
you are using a version of Xamarin Android earlier than 7.0, you must manually upload your APK via the Google
Play Developer Console. Also, you must have at least one APK already uploaded before you can use the
integrated workflow. If you have not yet uploaded your first APK, you must upload it manually. For more
information, see Manually Uploading the APK.
Creating a New Certificate, explained how to create a new certificate for signing Android apps. The next step is to
publish a signed app to Google Play:
1. Sign into your Google Play Developer account to create a new project that is linked to your Google Play
Developer account.
2. Create an OAuth Client that authenticates your app.
3. Enter the resulting Client ID and Client secret into Visual Studio.
4. Register your account with Visual Studio.
5. Sign the app with your certificate.
6. Publish your signed app to Google Play.
In Archive for Publishing, the Distribution Channel dialog presented two choices for distribution: Ad Hoc and
Google Play. If the Signing Identity dialog is displayed instead, click Back to return to the Distribution
Channel dialog. Select Google Play and click Next:
In the Signing Identity dialog, select the identity created in Creating a New Certificate and click Continue:
In the Google Play Accounts dialog, click the + button to add a new Google Play Account:
In the Register Google API Access dialog, you must provide the Client ID and Client secret that provides API
access to your Google Play Developer account:
The next section explains how to create a new Google API project and generate the needed Client ID and Client
secret.
Create a Google API Project
First, sign into your Google Play Developer account. If you do not already have a Google Play Developer account,
see Get Started with Publishing. Also, the Google Play Developer API Getting Started explains how to use the
Google Play Developer API. After you sign into the Google Play Developer Console, click Settings:
In the SETTINGS page, select API accessand click the Create new project button:
After a minute or so, the new API project is automatically generated and linked to your Google Play Developer
Console account.
The next step is to create an OAuth Client for the app (if one has not already been created). When users request
access to their private data using your app, your OAuth Client ID is used to authenticate your app. Click Create
OAuth Client to create a new OAuth client:
After a few seconds, a new Client ID is generated. Click View in Google Developers Console to see your new
Client ID in the Google Developer's Console:
The Client ID is displayed along its name and creation date. Click the Edit OAuth Client icon to view the Client
secret for your app:
The default name of the OAuth client is Google Play Android Developer. This can be changed to the name of
Xamarin.Android app, or any suitable name. In this example, the OAuth Client name is changed to the name of the
app, MyApp:
Click Saveto save changes. This returns to the Credentials page where to download the credentials by clicking on
the Download JSON icon :
This JSON file contains the Client ID and Client secret that you can cut and paste into the Sign and Distribute
dialog in the next step.
Register Google API Access
Visual Studio
Visual Studio for Mac
Use the Client ID and Client secret to complete the Google Play API Account dialog in Visual Studio for Mac. It
is possible to give the account a description – this makes it possible to register more than one Google Play
account and upload future APK's to different Google Play accounts. Copy the Client ID and Client secret to this
dialog and click Register:
A web browser will open and prompt you to sign into your Google Play Android Developer account (if you are
not already signed in). After you sign in, the following prompt is displayed in the web browser. Click Allow to
authorize the app:
Publish
After clicking Allow, the browser reports Received verification code. Closing... and the app is added to the list of
Google Play Accounts in Visual Studio. In the Google Play Accounts dialog, click Continue:
Next, the Google Play Track dialog is presented. Google Play offers four possible tracks for uploading your app:
Alpha – Used for uploading a very early version of the app to a small list of testers.
Beta – Used for uploading an early version of the app to a larger list of testers.
Rollout – Allows a percentage of users to receive an updated version of the app; this makes it possible to
slowly increase the percentage from say, 10% of users and increase it to 100% of users while you iron out
bugs.
Production – Select this track when the app is ready for full distribution from the Google Play store.
Choose which Google Play track will be used for uploading the app and click Upload. If you select Rollout, be
sure to enter a percentage value:
For more information about Google Play testing and staged rollouts, see Set up alpha/beta tests.
Next, a dialog is presented to enter the password for the signing certificate. Enter the password and click OK:
The Archive Manager displays the progress of the upload:
When the upload finishes, completion status is shown in the lower left hand corner of Visual Studio:
Troubleshooting
Note that one APK must have already been submitted to the Google Play store before the Publish to Google
Play will work. If an APK is not already uploaded the Publishing Wizard will display the following error in the
Errors pane:
When this error occures, manually upload an APK (such as an Ad-Hoc build) via the Google Play Developer
Console and use the Distribution Channel dialog for subsequent APK updates. For more information, see
Manually Uploading the APK. The version code of the APK must change with each upload, otherwise the
following error will occur:
To resolve this error, rebuild the app with a different version number and resubmit it to Google Play via the
Distribution Channel dialog.
Google Licensing Services
4/12/2018 • 2 minutes to read • Edit Online
Prior to Google Play, Android applications relied on the legacy Copy Protection provided by Google Market to
ensure that only authorized users could run applications on their devices. The limitations of the Copy Protection
mechanism made it a less-than-ideal solution for application protection.
Google Licensing is a replacement for this legacy Copy Protection mechanism. Google Licensing is a flexible,
secure, network-based service that Android applications may query to determine if an application is licensed to run
on a given device.
Google Licensing is flexible in that Android applications have full control over when to check the license, how often
to check the license, and how to handle the response from the licensing server.
Google Licensing is secure in that each response is signed using an RSA key pair that is shared exclusively between
the Google Play server and the application. Google Play provides a public key for developers that is embedded
within the Android application and is used to authenticate the responses. The Google Play server keeps the private
key internally.
An application that has implemented Google Licensing makes a request to a service hosted by the Google Play
application on the device. Google Play then sends this request on to the Google Licensing server, which responds
with the license status:
Some applications (some games, for instance) require more resources and assets than can be provided in the
maximum Android app size limit imposed by Google Play. This limit depends on the version of Android that your
APK is targeted for:
100MB for APKs that target Android 4.0 or higher (API level 14 or higher).
50MB for APKs that target Android 3.2 or lower (API level 13 or higher).
To overcome this limitation, Google Play will host and distribute two expansion files to go along with an APK,
allowing an application to indirectly exceed this limit.
On most devices, when an application is installed, expansion files will be downloaded along with the APK and will
be saved to the shared storage location (the SD card or the USB -mountable partition) on the device. On a few
older devices, the expansion files may not automatically install with the APK. In these situations, it is necessary for
the application to contain code that will download the expansion files when the user first runs the applications.
Expansion files are treated as opaque binary blobs (obb ) and may be up to 2GB in size. Android does not perform
any special processing on these files after they are downloaded – the files can be in any format that is appropriate
for the application. Conceptually, the recommended approach to expansion files is as follows:
Main expansion – This file is the primary expansion file for resources and assets that will not fit in the APK
size limit. The main expansion file should contain the primary assets that an application needs and should rarely
be updated.
Patch expansion – This is intended for small updates to the main expansion file. This file can be updated. It is
the responsibility of the application to perform any necessary patches or updates from this file.
The expansion files must be uploaded at the same time as the APK is uploaded. Google play does not allow an
expansion file to be uploaded to an existing APK or for existing APKs to be updated. If it is necessary to update an
expansion file, then a new APK must be uploaded with the versionCode updated.
[main|patch].<expansion-version>.<package-name>.obb
For example, if the APK version is 21, and the package name is mono.samples.helloworld , the main expansion file
will be named main.21.mono.samples.helloworld.
Download Process
When an application is installed from Google Play, the expansion files should be downloaded and saved along with
the APK. In certain situations this may not happen, or expansion files may be deleted. To handle this condition, an
app needs to check to see whether the expansion files exist and then download them, if necessary. The following
flowchart displays the recommended workflow of this process:
When an application starts up, it should check to see if the appropriate expansion files exist on the current device. If
they do not, then the application must make a request from Google Play’s Application Licensing. This check is
made by using the License Verification Library (LVL ), and must be made for both free and licensed applications. The
LVL is primarily used by paid applications to enforce license restrictions. However, Google has extended the LVL so
that it can be used with expansion libraries as well. Free applications have to perform the LVL check, but can ignore
the license restrictions. The LVL request is responsible for providing the following information about the expansion
files that the application requires:
File Size – The file sizes of the expansion files are used as part of the check that determines whether or not the
correct expansion files have already been downloaded.
Filenames – This is the file name (on the current device) to which the expansion packs must be saved.
URL for Download – The URL that should be used to download the expansion packs. This is unique for every
download and will expire shortly after it is provided.
After the LVL check has been performed, the application should download the expansion files, taking into
consideration the following points as part of the download:
The device may not have enough space to store the expansion files.
If Wi-Fi is not available, then the user should be allowed to pause or cancel the download to prevent unwanted
data charges.
The expansion files are downloaded in the background to avoid blocking user interactions.
While the download is occurring in the background, a progress indicator should be displayed.
Errors that occur during the download are gracefully handled and recoverable.
Architectural Overview
When the main activity starts, it checks to see if the expansion files are downloaded. If the files are downloaded,
they must be checked for validity.
If the expansion files have not been downloaded or if the current files are invalid, then new expansion files must be
downloaded. A bounded service is created as part of the application. When the main activity of the application is
started, it uses the bounded service to perform a check against the Google Licensing services to find out the
expansion file names and the URL of the files to download. The bounded service will then download the files on a
background thread.
To ease the effort required to integrate expansion files into an application, Google created several libraries in Java.
The libraries in question are:
Downloader Library – This is a library that reduces the effort required to integrate expansion files in an
application. The library will download the expansion files in a background service, display user notifications,
handle network connectivity issues, resume downloads, etc.
License Verification Library (LVL ) – A library for making and processing the calls to the Application
Licensing services. It can also be used to perform licensing checks, to see if the application is authorized for use
on the device.
APK Expansion Zip Library (optional) – If the expansion files are in a zip file, this library will act as a content
provider and allow an application to read resources and assets directly from the zip file without having to
expand the zip file.
These libraries have been ported to C# and are available under the Apache 2.0 license. To quickly integrate
expansion files into an existing application, these libraries can be added to an existing Xamarin.Android application.
The code is available at the Android.Play.ExpansionLibrary on GitHub.
Manually Uploading the APK
4/12/2018 • 7 minutes to read • Edit Online
The first time an APK is submitted to Google Play (or if an early version of Xamarin.Android is used) the APK
must be manually uploaded through the Google Play Developer Console. This guide explains the steps required
for this process.
If you already have an existing app registered with Google Play, click the Add new application button:
When the ADD NEW APPLICATION dialog is displayed, enter the name of the app and click Upload APK:
The next screen allows the app to be published for alpha testing, beta testing, or production. In the following
example, the ALPHA TESTING tab is selected. Because MyApp does not use licensing services, the Get license
key button does not have to be clicked for this example. Here, the Upload your first APK to Alpha button is
clicked to publish to the Alpha channel:
The UPLOAD NEW APK TO ALPHA dialog is displayed. The APK can be uploaded by either clicking the
Browse files button or by dragging-and-dropping the APK:
Be sure to upload the release-ready APK that is to be distributed. The next dialog indicates the progress of the
APK upload:
Store Listing
Click Store Listing in the Google Play Developer Console to enter the information that Google Play will
display to potentials users of the application:
Graphics Assets
Scroll down to the GRAPHICS ASSETS section of the Store Listing page:
All of the promotional assets that were prepared earlier are uploaded in this section. Guidance is provided as to
what promotional assets must be provided and what format they should be provided in.
Categorization
After the GRAPHICS ASSETS section is a CATEGORIZATION section, select the application type and category:
It is possible to provide a URL for the privacy policy of the App in the PRIVACY POLICY section, as indicated
above.
Content Rating
Click Content Rating in the Google Play Developer Console. In this page, you specify the content rating for
your app. Google Play requires that all applications specify a content rating. Click the Continue button to
complete the content rating questionaire:
All applications on Google Play must be rated according to the Google Play ratings system. In addition to the
content rating, all applications must adhere to Google's Developer Content Policy.
The following lists the four levels in the Google Play rating system and provides some guidelines as features or
content that would require or force the rating level:
Everyone – May not access, publish, or share location data. May not host any user-generated content. May
not enable communication between users.
Low maturity – Applications that access, but do not share, location data. Depictions of mild or cartoon
violence.
Medium maturity – References to drugs, alcohol or tobacco. Gambling themes or simulated gambling.
Inflammatory content. Profanity or crude humor. Suggestive or sexual references. Intense fantasy violence.
Realistic violence. Allowing users to find each other. Allowing users to communicate with each other.
Sharing of a user's location data.
High maturity – A focus on the consumption or sale of alcohol, tobacco, or drugs. A focus on suggestive
or sexual references. Graphic violence.
The items in the Medium maturity list are subjective, as such it is possible that a guideline that may seem to
dictate a Medium maturity rating may be intense enough to warrant a High maturity rating.
Other Information
Scroll down further to specify whether the app contains ads. Also, the DEVICE CATEGORIES section provides
options to optionally distribute the app for Android Wear, Android TV, or Android Auto:
After this section are additional options that may be selected, such as opting into Designed for Families and
distributing the app through Google Play for Education.
Consent
At the bottom of the Pricing & Distribution page is the CONSENT section. This is a mandatory section and is
used to declare that the application meets the Android Content Guidelines and acknowledgement that the
application is subject to U.S. export laws:
There is much more to publishing a Xamarin.Android app than can be covered in this guide. For more information
about publishing your app in Google Play, see Welcome to the Google Play Developer Console Help Center.
uses-permission – This element is used to infer certain hardware features that are required for the
application to run that may not have been properly declared with a <uses-feature> element. For example,
if an application requests permission to use the camera, then Google Play assumes that devices must have
a camera, even if there is no <uses-feature> element declaring the camera. This element may be set with
the Android.App.UsesPermissionsAttribute . For example:
[assembly: UsesPermission(Manifest.Permission.Camera)]
uses-sdk – The element is used to declare the minimum Android API Level required for the application.
This element may set in the Xamarin.Android options of a Xamarin.Android project.
compatible-screens – This element is used to filter applications that do not match the screen size and
density specified by this element. Most applications should not use this filter. It is intended for specific high
performance games or applications that required strict controls on application distribution. The
<support-screen> attribute mentioned above is preferred.
supports-gl-texture – This element is used to declare GL texture compression formations that the
application requires. Most applications should not use this filter. It is intended for specific high performance
games or applications that required strict controls on application distribution.
For more information about configuring the app manifest, see the Android App Manifest topic.
Publishing to the Amazon App Store
4/12/2018 • 2 minutes to read • Edit Online
The Amazon Mobile App Distribution Program enables mobile app developers to publish their applications on
Amazon. This section briefly covers the Amazon App Store for Android.
Amazon does not limit the size of APKs. However, if an APK is larger than 30MB, then it will use FTP for
distribution rather than the Amazon Mobile App Distribution Portal.
Approval Process
Once an application has been submitted, it goes through an approval process. Amazon will review your application
to ensure that it works as outlined in the product description, does not put customer data at risk, and will not
impair the operation of the device. Once the approval process is complete, Amazon will send out a notification and
distribute the application.
Publishing Independently
6/27/2018 • 3 minutes to read • Edit Online
It is possible to publish an application without using any of the existing Android marketplaces. This section will
explain these other publishing methods and the licensing levels of Xamarin.Android.
Xamarin Licensing
Four licenses are available for development, deployment, and distribution of Xamarin.Android apps:
Visual Studio Community – For students, small teams, and OSS developers who use Windows.
Visual Studio Professional – For individual developers or small teams (Windows only). This license offers
a standard or cloud subscription, access to additional Xamarin University content, and no usage restrictions.
Visual Studio Enterprise – For teams of any size (Windows only). This license includes enterprise
capabilities, a standard or cloud subscription.
Visit the visualstudio.com to download the Community Edition or to learn more about purchasing the Professional
and Enterprise editions.
Publishing by E-Mail
Attaching the release APK to an e-mail is a quick and easy way to distribute an application to users. When the user
opens the e-mail on an Android-powered device, Android will recognize the APK attachment and display an
Install button as shown in the following image:
Although distribution via e-mail is simple, it provides few protections against piracy or unauthorized distribution. It
is best reserved for situations where the recipients of the application are few, and they are trusted not to distribute
the application.
Publishing by Web
It is possible to distribute an application by a web server. This is accomplished by uploading the application to the
web server, and then providing a download link to users. When an Android-powered device browses to a link and
then downloads the application, that application will automatically be installed once the download is complete.
$ adb devices
List of devices attached
0149B2EC03012005device
After the connected devices have been confirmed, the application can be installed by issuing the install
command with adb:
If the application is already installed, the adb install will be unable to install the APK and will report a failure, as
shown in the following example:
It will be necessary to uninstall the application from the device. First, issue the adb uninstall command:
This guide will discuss the differences between a system app and a user app, and how to install a Xamarin.Android
application as a system application. This guide applies to authors of custom Android ROM images. It will not
explain how to create a custom ROM.
System App
Authors of custom Android ROM images or manufacturers of Android devices may wish to include a
Xamarin.Android application as a system app when distributing a ROM or a device. A system app is an app that is
considered to be important to the functioning of the device or provide functionality that the custom ROM author
always wants to be available.
System apps are installed in the folder /system/app/ (a read-only directory on the file system) and cannot be
deleted or moved by the user unless that user has root access. In contrast, an application that is installed by the
user (typically from Google Play or by sideloading the app) is known as a user app. User apps can be deleted by
the user and in many cases can be moved to a different location on the device (such as some kind of external
storage).
System apps behave exactly like user apps, but have the following notable exceptions:
System apps are upgradable just like a normal user app. However, because a copy of the app always exists
in /system/app/, it is always possible to roll back the application to the original version.
System apps may be granted certain system-only permissions that are not available to a user app. An
example of a system-only permission is BLUETOOTH_PRIVILEGED , which allows applications to pair with
Bluetooth devices without any user interaction.
It is possible to distribute a Xamarin.Android app as a system application. In addition to providing an APK to the
custom ROM, there are two shared libraries, libmonodroid.so and libmonosgen-2.0.so that must be manually
copied from the APK to the filesytem of the ROM image. This guide will explain the steps involved.
Restrictions
This guide applies to authors of custom Android ROM images. It will not explain how to create a custom ROM.
This guide assumes familiarity with packaging a release APK for a Xamarin.Android and an understanding of CPU
Architectures for Android applications.
Summary
This guide discussed the difference between a system app and a user app, and explained how to install a
Xamarin.Android application as a system app.
Related Links
Publishing an Application
CPU Architectures
BLUETOOTH_PRIVILEGED
ABI Management
Advanced Concepts and Internals
5/21/2018 • 2 minutes to read • Edit Online
This section contains topics that explain the architecture, API design, and limitations of Xamarin.Android. In
addition, it includes topics that explain its garbage collection implementation and the assemblies that are available
in Xamarin.Android. Because Xamarin.Android is open-source, it is also possible to understand the inner workings
of Xamarin.Android by examining its source code.
Architecture
This article explains the underlying architecture behind a Xamarin.Android application. It explains how
Xamarin.Android applications run inside a Mono execution environment alongside with the Android runtime
Virtual Machine and explains such key concepts as Android Callable Wrappers and Managed Callable Wrappers.
API Design
In addition to the core Base Class Libraries that are part of Mono, Xamarin.Android ships with bindings for various
Android APIs to allow developers to create native Android applications with Mono.
At the core of Xamarin.Android there is an interop engine that bridges the C# world with the Java world and
provides developers with access to the Java APIs from C# or other .NET languages.
Assemblies
Xamarin.Android ships with several assemblies. Just as Silverlight is an extended subset of the desktop .NET
assemblies, Xamarin.Android is also an extended subset of several Silverlight and desktop .NET assemblies.
Architecture
7/12/2018 • 8 minutes to read • Edit Online
Xamarin.Android applications run within the Mono execution environment. This execution environment runs side-
by-side with the Android Runtime (ART) virtual machine. Both runtime environments run on top of the Linux
kernel and expose various APIs to the user code that allows developers to access the underlying system. The
Mono runtime is written in the C language.
You can be using the System, System.IO, System.Net and the rest of the .NET class libraries to access the
underlying Linux operating system facilities.
On Android, most of the system facilities like Audio, Graphics, OpenGL and Telephony are not available directly to
native applications, they are only exposed through the Android Runtime Java APIs residing in one of the Java.*
namespaces or the Android.* namespaces. The architecture is roughly like this:
Xamarin.Android developers access the various features in the operating system either by calling into .NET APIs
that they know (for low -level access) or using the classes exposed in the Android namespaces which provides a
bridge to the Java APIs that are exposed by the Android Runtime.
For more information on how the Android classes communicate with the Android Runtime classes see the API
Design document.
Application Packages
Android application packages are ZIP containers with a .apk file extension. Xamarin.Android application packages
have the same structure and layout as normal Android packages, with the following additions:
The application assemblies (containing IL ) are stored uncompressed within the assemblies folder. During
process startup in Release builds the .apk is mmap () ed into the process and the assemblies are loaded
from memory. This permits faster app startup, as assemblies do not need to be extracted prior to execution.
- Note: Assembly location information such as Assembly.Location and Assembly.CodeBase cannot be relied
upon in Release builds. They do not exist as distinct filesystem entries, and they have no usable location.
Native libraries containing the Mono runtime are present within the .apk . A Xamarin.Android application
must contain native libraries for the desired/targeted Android architectures, e.g. armeabi , armeabi-v7a ,
x86 . Xamarin.Android applications cannot run on a platform unless it contains the appropriate runtime
libraries.
Xamarin.Android applications also contain Android Callable Wrappers to allow Android to call into managed
code.
If we create an instance, Dispose() of it, and cause the Managed Callable Wrapper to be re-created:
If the subclass does contain an (IntPtr, JniHandleOwnership ) constructor, then a new instance of the type will be
created. As a result, the instance will appear to "lose" all instance data, as it's a new instance. (Note that the Value is
null.)
Only Dispose() of managed callable wrapper subclasses when you know that the Java object will not be used
anymore, or the subclass contains no instance data and a (IntPtr, JniHandleOwnership ) constructor has been
provided.
Application Startup
When an activity, service, etc. is launched, Android will first check to see if there is already a process running to
host the activity/service/etc. If no such process exists, then a new process will be created, the AndroidManifest.xml
is read, and the type specified in the /manifest/application/@android:name attribute is loaded and instantiated.
Next, all types specified by the /manifest/application/provider/@android:name attribute values are instantiated
and have their ContentProvider.attachInfo%28) method invoked. Xamarin.Android hooks into this by adding a
mono.MonoRuntimeProvider ContentProvider to AndroidManifest.xml during the build process. The
mono.MonoRuntimeProvider.attachInfo () method is responsible for loading the Mono runtime into the process.
Any attempts to use Mono prior to this point will fail. ( Note: This is why types which subclass
Android.App.Application need to provide an (IntPtr, JniHandleOwnership) constructor, as the Application instance
is created before Mono can be initialized.)
Once process initialization has completed, AndroidManifest.xml is consulted to find the class name of the
activity/service/etc. to launch. For example, the /manifest/application/activity/@android:name attribute is used to
determine the name of an Activity to load. For Activities, this type must inherit android.app.Activity. The specified
type is loaded via Class.forName() (which requires that the type be a Java type, hence the Android Callable
Wrappers), then instantiated. Creation of an Android Callable Wrapper instance will trigger creation of an instance
of the corresponding C# type. Android will then invoke Activity.onCreate(Bundle) , which will cause the
corresponding Activity.OnCreate(Bundle) to be invoked, and you're off to the races.
Available Assemblies
7/12/2018 • 2 minutes to read • Edit Online
Xamarin.iOS, Xamarin.Android, and Xamarin.Mac all ship with over a dozen assemblies. Just as Silverlight is an
extended subset of the desktop .NET assemblies, Xamarin platforms is also an extended subset of several
Silverlight and desktop .NET assemblies.
Xamarin platforms are not ABI compatible with existing assemblies compiled for a different profile. You must
recompile your source code to generate assemblies targeting the correct profile ( just as you need to recompile
source code to target Silverlight and .NET 3.5 separately).
Xamarin.Mac applications can be compiled in three modes: one that uses Xamarin's curated Mobile Profile, the
Xamarin.Mac .NET 4.5 Framework which allows you target existing full desktop assemblies, and an unsupported
one that uses the .NET API found in a system Mono installation. For more information, please see our Target
Frameworks documentation.
Supported Assemblies
ASSEMBLY API COMPATIBILITY XAMARIN IOS XAMARIN ANDROID XAMARIN MAC
FSharp.Core.dll ✓ ✓ ✓
Microsoft.CSharp.dll ✓ ✓ ✓
Mono.CSharp.dll ✓ ✓ ✓
Mono.Dynamic. ✓
Interpreter.dll
ASSEMBLY API COMPATIBILITY XAMARIN IOS XAMARIN ANDROID XAMARIN MAC
MonoTouch.Dialog- ✓
1.dll
MonoTouch. ✓
NUnitLite.dll
mscorlib.dll Silverlight ✓ ✓ ✓
System. ✓ ✓ ✓
ComponentModel.
Composition.dll
System. ✓ ✓ ✓
ComponentModel.
DataAnnotations.dll
System.Core.dll Silverlight ✓ ✓ ✓
System.IO. ✓ ✓ ✓
Compression
ASSEMBLY API COMPATIBILITY XAMARIN IOS XAMARIN ANDROID XAMARIN MAC
System.IO. ✓ ✓ ✓
Compression.
FileSystem
System.Json.dll Silverlight ✓ ✓ ✓
System.Net.Http.dll ✓ ✓ ✓
System.Numerics.dll ✓ ✓ ✓
System.Runtime. Silverlight ✓ ✓ ✓
Serialization.dll
System.ServiceModel. ✓ ✓ ✓
Internals.dll
System.Windows.dll ✓ ✓ ✓
System.Xml.Serializati ✓ ✓ ✓
on.dll
Java.Interop.dll ✓
Mono.Android.dll ✓
Mono.Android. ✓
Export.dll
Mono.Posix.dll ✓
System. ✓
EnterpriseServices.dll
Xamarin.Android. ✓
NUnitLite.dll
Xamarin.Mac.dll ✓
Overview
In addition to the core Base Class Libraries that are part of Mono, Xamarin.Android ships with bindings for
various Android APIs to allow developers to create native Android applications with Mono.
At the core of Xamarin.Android there is an interop engine that bridges the C# world with the Java world and
provides developers with access to the Java APIs from C# or other .NET languages.
Design Principles
These are some of our design principles for the Xamarin.Android binding
Conform to the .NET Framework Design Guidelines.
Allow developers to subclass Java classes.
Subclass should work with C# standard constructs.
Derive from an existing class.
Call base constructor to chain.
Overriding methods should be done with C#'s override system.
Make common Java tasks easy, and hard Java tasks possible.
Expose JavaBean properties as C# properties.
Expose a strongly typed API:
Increase type-safety.
Minimize runtime errors.
Get IDE intellisense on return types.
Allows for IDE popup documentation.
Encourage in-IDE exploration of the APIs:
Utilize Framework Alternatives to Minimize Java Classlib exposure.
Expose C# delegates (lambdas, anonymous methods and System.Delegate) instead of single-
method interfaces when appropriate and applicable.
Provide a mechanism to call arbitrary Java libraries ( Android.Runtime.JNIEnv).
Assemblies
Xamarin.Android includes a number of assemblies that constitute the MonoMobile Profile. The Assemblies page
has more information.
The bindings to the Android platform are contained in the Mono.Android.dll assembly. This assembly contains the
entire binding for consuming Android APIs and communicating with the Android runtime VM.
Binding Design
Collections
The Android APIs utilize the java.util collections extensively to provide lists, sets, and maps. We expose these
elements using the System.Collections.Generic interfaces in our binding. The fundamental mappings are:
java.util.Set maps to system type ICollection, helper class Android.Runtime.JavaSet.
java.util.List maps to system type IList, helper class Android.Runtime.JavaList.
java.util.Map<K,V> maps to system type IDictionary<TKey,TValue>, helper class
Android.Runtime.JavaDictionary<K,V>.
java.util.Collection maps to system type ICollection, helper class Android.Runtime.JavaCollection.
We have provided helper classes to facilitate faster copyless marshaling of these types. When possible, we
recommend using these provided collections instead of the framework provided implementation, like List<T> or
Dictionary<TKey, TValue> . The Android.Runtime implementations utilize a native Java collection internally and
therefore do not require copying to and from a native collection when passing to an Android API member.
You can pass any interface implementation to an Android method accepting that interface, e.g. pass a List<int>
to the ArrayAdapter<int>(Context, int, IList<int>) constructor. However, for all implementations except for the
Android.Runtime implementations, this involves copying the list from the Mono VM into the Android runtime
VM. If the list is later changed within the Android runtime (e.g. by invoking the ArrayAdapter<T>.Add(T) method),
those changes will not be visible in managed code. If a JavaList<int> were used, those changes would be visible.
Rephrased, collections interface implementations that are not one of the above listed Helper Classes only
marshal [In]:
// This fails:
var badSource = new List<int> { 1, 2, 3 };
var badAdapter = new ArrayAdapter<int>(context, textViewResourceId, badSource);
badAdapter.Add (4);
if (badSource.Count != 4) // true
throw new InvalidOperationException ("this is thrown");
// this works:
var goodSource = new JavaList<int> { 1, 2, 3 };
var goodAdapter = new ArrayAdapter<int> (context, textViewResourceId, goodSource);
goodAdapter.Add (4);
if (goodSource.Count != 4) // false
throw new InvalidOperationException ("should not be reached.");
Properties
Java methods are transformed into properties, when appropriate:
The Java method pair T getFoo() and void setFoo(T) are transformed into the Foo property. Example:
Activity.Intent.
The Java method getFoo() is transformed into the read-only Foo property. Example:
Context.PackageName.
Set-only properties are not generated.
Properties are not generated if the property type would be an array.
Events and Listeners
The Android APIs are built on top of Java and its components follow the Java pattern for hooking up event
listeners. This pattern tends to be cumbersome as it requires the user to create an anonymous class and declare
the methods to override, for example, this is how things would be done in Android with Java:
Note that both of the above mechanisms are available with Xamarin.Android. You can implement a listener
interface and attach it with View.SetOnClickListener, or you can attach a delegate created via any of the usual C#
paradigms to the Click event.
When the listener callback method has a void return, we create API elements based on an
EventHandler<TEventArgs> delegate. We generate an event like the above example for these listener types.
However, if the listener callback returns a non-void and non- boolean value, events and EventHandlers are not
used. We instead generate a specific delegate for the signature of the callback and add properties instead of
events. The reason is to deal with delegate invocation order and return handling. This approach mirrors what is
done with the Xamarin.iOS API.
C# events or properties are only automatically generated if the Android event-registration method:
1. Has a set prefix, e.g. setOnClickListener.
2. Has a void return type.
3. Accepts only one parameter, the parameter type is an interface, the interface has only one method, and the
interface name ends in Listener , e.g. View.OnClick Listener.
Furthermore, if the Listener interface method has a return type of boolean instead of void, then the generated
EventArgs subclass will contain a Handled property. The value of the Handled property is used as the return value
for the Listener method, and it defaults to true .
For example, the Android View.setOnKeyListener() method accepts the View.OnKeyListener interface, and the
View.OnKeyListener.onKey(View, int, KeyEvent) method has a boolean return type. Xamarin.Android generates a
corresponding View.KeyPress event, which is an EventHandler<View.KeyEventArgs>. The KeyEventArgs class in
turn has a View.KeyEventArgs.Handled property, which is used as the return value for the
View.OnKeyListener.onKey () method.
We intend to add overloads for other methods and ctors to expose the delegate-based connection. Also, listeners
with multiple callbacks require some additional inspection to determine if implementing individual callbacks is
reasonable, so we are converting these as they are identified. If there is no corresponding event, listeners must be
used in C#, but please bring any that you think could have delegate usage to our attention. We have also done
some conversions of interfaces without the "Listener" suffix when it was clear they would benefit from a delegate
alternative.
All of the listeners interfaces implement the Android.Runtime.IJavaObject interface, because of the implementation
details of the binding, so listener classes must implement this interface. This can be done by implementing the
listener interface on a subclass of Java.Lang.Object or any other wrapped Java object, such as an Android activity.
Runnables
Java utilizes the java.lang.Runnable interface to provide a delegation mechanism. The java.lang.Thread class is a
notable consumer of this interface. Android has employed the interface in the API as well.
Activity.runOnUiThread() and View.post() are notable examples.
The Runnable interface contains a single void method, run(). It therefore lends itself to binding in C# as a
System.Action delegate. We have provided overloads in the binding which accept an Action parameter for all API
members which consume a Runnable in the native API, e.g. Activity.RunOnUiThread() and View.Post().
We left the IRunnable overloads in place instead of replacing them since several types implement the interface
and can therefore be passed as runnables directly.
Inner Classes
Java has two different types of nested classes: static nested classes and non-static classes.
Java static nested classes are identical to C# nested types.
Non-static nested classes, also called inner classes, are significantly different. They contain an implicit reference to
an instance of their enclosing type and cannot contain static members (among other differences outside the scope
of this overview ).
When it comes to binding and C# use, static nested classes are treated as normal nested types. Inner classes,
meanwhile, have two significant differences:
1. The implicit reference to the containing type must be provided explicitly as a constructor parameter.
2. When inheriting from an inner class, the inner class must be nested within a type that inherits from the
containing type of the base inner class, and the derived type must provide a constructor of the same type as
the C# containing type.
For example, consider the Android.Service.Wallpaper.WallpaperService.Engine inner class. Since it's an inner class,
the WallpaperService.Engine() constructor takes a reference to a WallpaperService instance (compare and
contrast to the Java WallpaperService.Engine() constructor, which takes no parameters).
An example derivation of an inner class is CubeWallpaper.CubeEngine:
Note how CubeWallpaper.CubeEngine is nested within CubeWallpaper , CubeWallpaper inherits from the containing
class of WallpaperService.Engine , and CubeWallpaper.CubeEngine has a constructor which takes the declaring type -
- CubeWallpaper in this case -- all as specified above.
Interfaces
Java interfaces can contain three sets of members, two of which cause problems from C#:
1. Methods
2. Types
3. Fields
Java interfaces are translated into two types:
1. An (optional) interface containing method declarations. This interface has the same name as the Java
interface, except it also has an ' I ' prefix.
2. An (optional) static class containing any fields declared within the Java interface.
Nested types are "relocated" to be siblings of the enclosing interface instead of nested types, with the enclosing
interface name as a prefix.
For example, consider the android.os.Parcelable interface. The Parcelable interface contains methods, nested
types, and constants. The Parcelable interface methods are placed into the Android.OS.IParcelable interface. The
Parcelable interface constants are placed into the Android.OS.ParcelableConsts type. The nested
android.os.Parcelable.ClassLoaderCreator and android.os.Parcelable.Creator types are currently not bound due to
limitations in our generics support; if they were supported, they would be present as the
Android.OS.IParcelableClassLoaderCreator and Android.OS.IParcelableCreator interfaces. For example, the
nested android.os.IBinder.DeathRecpient interface is bound as the Android.OS.IBinderDeathRecipient interface.
NOTE
Beginning with Xamarin.Android 1.9, Java interface constants are duplicated in an effort to simplify porting Java code. This
helps to improve porting Java code that relies on android provider interface constants.
Resources
Images, layout descriptions, binary blobs and string dictionaries can be included in your application as resource
files. Various Android APIs are designed to operate on the resource IDs instead of dealing with images, strings or
binary blobs directly.
For example, a sample Android app that contains a user interface layout ( main.axml ), an internationalization table
string ( strings.xml ) and some icons ( drawable-*/icon.png ) would keep its resources in the "Resources"
directory of the application:
Resources/
drawable-hdpi/
icon.png
drawable-ldpi/
icon.png
drawable-mdpi/
icon.png
layout/
main.axml
values/
strings.xml
The native Android APIs do not operate directly with filenames, but instead operate on resource IDs. When you
compile an Android application that uses resources, the build system will package the resources for distribution
and generate a class called Resource that contains the tokens for each one of the resources included. For example,
for the above Resources layout, this is what the R class would expose:
You would then use Resource.Drawable.icon to reference the drawable/icon.png file, or Resource.Layout.main to
reference the layout/main.xml file, or Resource.String.first_string to reference the first string in the dictionary
file values/strings.xml .
Xamarin.Android uses Mono's Simple Generational garbage collector. This is a mark-and-sweep garbage collector
with two generations and a large object space, with two kinds of collections:
Minor collections (collects Gen0 heap)
Major collections (collects Gen1 and large object space heaps).
NOTE
In the absence of an explicit collection via GC.Collect() collections are on demand, based upon heap allocations. This is not a
reference counting system; objects will not be collected as soon as there are no outstanding references, or when a scope
has exited. The GC will run when the minor heap has run out of memory for new allocations. If there are no allocations, it will
not run.
Minor collections are cheap and frequent, and are used to collect recently allocated and dead objects. Minor
collections are performed after every few MB of allocated objects. Minor collections may be manually performed
by calling GC.Collect (0)
Major collections are expensive and less frequent, and are used to reclaim all dead objects. Major collections are
performed once memory is exhausted for the current heap size (before resizing the heap). Major collections may
be manually performed by calling GC.Collect () or by calling GC.Collect (int) with the argument
GC.MaxGeneration.
Object Cycles
Peer objects are logically present within both the Android runtime and Mono VM's. For example, an
Android.App.Activity managed peer instance will have a corresponding android.app.Activity framework peer Java
instance. All objects that inherit from Java.Lang.Object can be expected to have representations within both VMs.
All objects that have representation in both VMs will have lifetimes which are extended compared to objects which
are present only within a single VM (such as a System.Collections.Generic.List<int> ). Calling GC.Collect won't
necessarily collect these objects, as the Xamarin.Android GC needs to ensure that the object isn't referenced by
either VM before collecting it.
To shorten object lifetime, Java.Lang.Object.Dispose() should be invoked. This will manually "sever" the connection
on the object between the two VMs by freeing the global reference, thus allowing the objects to be collected faster.
Automatic Collections
Beginning with Release 4.1.0, Xamarin.Android automatically performs a full GC when a gref threshold is crossed.
This threshold is 90% of the known maximum grefs for the platform: 1800 grefs on the emulator (2000 max), and
46800 grefs on hardware (maximum 52000). Note: Xamarin.Android only counts the grefs created by
Android.Runtime.JNIEnv, and will not know about any other grefs created in the process. This is a heuristic only.
When an automatic collection is performed, a message similar to the following will be printed to the debug log:
The occurrence of this is non-deterministic, and may happen at inopportune times (e.g. in the middle of graphics
rendering). If you see this message, you may want to perform an explicit collection elsewhere, or you may want to
try to reduce the lifetime of peer objects.
GC Bridge Options
Xamarin.Android offers transparent memory management with Android and the Android runtime. It is
implemented as an extension to the Mono garbage collector called the GC Bridge.
The GC Bridge works during a Mono garbage collection and figures out which peer objects needs their "liveness"
verified with the Android runtime heap. The GC Bridge makes this determination by doing the following steps (in
order):
1. Induce the mono reference graph of unreachable peer objects into the Java objects they represent.
2. Perform a Java GC.
3. Verify which objects are really dead.
This complicated process is what enables subclasses of Java.Lang.Object to freely reference any objects; it
removes any restrictions on which Java objects can be bound to C#. Because of this complexity, the bridge process
can be very expensive and it can cause noticeable pauses in an application. If the application is experiencing
significant pauses, it's worth investigating one of the following three GC Bridge implementations:
Tarjan - A completely new design of the GC Bridge based on Robert Tarjan's algorithm and backwards
reference propagation. It has the best performance under our simulated workloads, but it also has the larger
share of experimental code.
New - A major overhaul of the original code, fixing two instances of quadratic behavior but keeping the
core algorithm (based on Kosaraju's algorithm for finding strongly connected components).
Old - The original implementation (considered the most stable of the three). This is the bridge that an
application should use if the GC_BRIDGE pauses are acceptable.
The only way to figure out which GC Bridge works best is by experimenting in an application and analyzing the
output. There are two ways to collect the data for benchmarking:
Enable logging - Enable logging (as describe in the Configuration section) for each GC Bridge option, then
capture and compare the log outputs from each setting. Inspect the GC messages for each option; in
particular, the GC_BRIDGE messages. Pauses up to 150ms for non-interactive applications are tolerable, but
pauses above 60ms for very interactive applications (such as games) are a problem.
Enable bridge accounting - Bridge accounting will display the average cost of the objects pointed by each
object involved in the bridge process. Sorting this information by size will provide hints as to what is
holding the largest amount of extra objects.
To specify which GC_BRIDGE option an application should us, pass bridge-implementation=old ,
bridge-implementation=new or bridge-implementation=tarjan to the MONO_GC_PARAMS enviroment variable, for
example:
MONO_GC_PARAMS=bridge-implementation=tarjan
The default setting is Tarjan. If you find a regression, you may find it necessary to set this option to Old. Also, you
may choose to use the more stable Old option if Tarjan does not produce an improvement in performance.
Helping the GC
There are multiple ways to help the GC to reduce memory use and collection times.
Disposing of Peer instances
The GC has an incomplete view of the process and may not run when memory is low because the GC doesn't
know that memory is low.
For example, an instance of a Java.Lang.Object type or derived type is at least 20 bytes in size (subject to change
without notice, etc., etc.). Managed Callable Wrappers do not add additional instance members, so when you have
a Android.Graphics.Bitmap instance that refers to a 10MB blob of memory, Xamarin.Android's GC won't know that
– the GC will see a 20-byte object and will be unable to determine that it's linked to Android runtime-allocated
objects that's keeping 10MB of memory alive.
It is frequently necessary to help the GC. Unfortunately, GC.AddMemoryPressure() and
GC.RemoveMemoryPressure() are not supported, so if you know that you just freed a large Java-allocated object
graph you may need to manually call GC.Collect() to prompt a GC to release the Java-side memory, or you can
explicitly dispose of Java.Lang.Object subclasses, breaking the mapping between the managed callable wrapper
and the Java instance. For example, see Bug 1084.
NOTE
You must be extremely careful when disposing of Java.Lang.Object subclass instances.
To minimize the possibility of memory corruption, observe the following guidelines when calling Dispose() .
Sharing Between Multiple Threads
If the Java or managed instance may be shared between multiple threads, it should not be Dispose() d, ever. For
example, Typeface.Create() may return a cached instance. If multiple threads provide the same arguments, they
will obtain the same instance. Consequently, Dispose() ing of the Typeface instance from one thread may
invalidate other threads, which can result in ArgumentException s from JNIEnv.CallVoidMethod() (among others)
because the instance was disposed from another thread.
Disposing Bound Java Types
If the instance is of a bound Java type, the instance can be disposed of as long as the instance won't be reused
from managed code and the Java instance can't be shared amongst threads (see previous Typeface.Create()
discussion). (Making this determination may be difficult.) The next time the Java instance enters managed code, a
new wrapper will be created for it.
This is frequently useful when it comes to Drawables and other resource-heavy instances:
The above is safe because the Peer that Drawable.CreateFromPath() returns will refer to a Framework peer, not a
User peer. The Dispose() call at the end of the using block will break the relationship between the managed
Drawable and framework Drawable instances, allowing the Java instance to be collected as soon as the Android
runtime needs to. This would not be safe if Peer instance referred to a User peer; here we're using "external"
information to know that the Drawable cannot refer to a User peer, and thus the Dispose() call is safe.
Disposing Other Types
If the instance refers to a type that isn't a binding of a Java type (such as a custom Activity ), DO NOT call
Dispose() unless you know that no Java code will call overridden methods on that instance. Failure to do so
results in NotSupportedException s.
For example, if you have a custom click listener:
You should not dispose of this instance, as Java will attempt to invoke methods on it in the future:
// BAD CODE; DO NOT USE
Button b = FindViewById<Button> (Resource.Id.myButton);
using (var listener = new MyClickListener ())
b.SetOnClickListener (listener);
This situation often occurs when the first dispose of an object causes a member to become null, and then a
subsequent access attempt on this null member causes an exception to be thrown. Specifically, the object's Handle
(which links a managed instance to its underlying Java instance) is invalidated on the first dispose, but managed
code still attempts to access this underlying Java instance even though it is no longer available (see Managed
Callable Wrappers for more about the mapping between Java instances and managed instances).
A good way to prevent this exception is to explicitly verify in your Dispose method that the mapping between the
managed instance and the underlying Java instance is still valid; that is, check to see if the object's Handle is null (
IntPtr.Zero ) before accessing its members. For example, the following Dispose method accesses a childViews
object:
If an initial dispose pass causes childViews to have an invalid Handle , the for loop access will throw an
ArgumentException . By adding an explicit Handle null check before the first childViews access, the following
Dispose method prevents the exception from occuring:
class MyClass : Java.Lang.Object, ISomeInterface
{
protected override void Dispose (bool disposing)
{
base.Dispose (disposing);
When is constructed, the object graph will contain 10004 instances (1x BadActivity , 1x strings , 1x
BadActivity
string[] held by strings , 10000x string instances), all of which will need to be scanned whenever the
BadActivity instance is scanned.
This can have detrimental impacts on your collection times, resulting in increased GC pause times.
You can help the GC by reducing the size of object graphs which are rooted by User peer instances. In the above
example, this can be done by moving BadActivity.strings into a separate class which doesn't inherit from
Java.Lang.Object:
class HiddenReference<T> {
int id;
public HiddenReference ()
{
lock (table) {
id = idgen ++;
}
}
~HiddenReference ()
{
lock (table) {
table.Remove (id);
}
}
public T Value {
get { lock (table) { return table [id]; } }
set { lock (table) { table [id] = value; } }
}
}
Minor Collections
Minor collections may be manually performed by calling GC.Collect(0). Minor collections are cheap (when
compared to major collections), but do have a significant fixed cost, so you don't want to trigger them too often,
and should have a pause time of a few milliseconds.
If your application has a "duty cycle" in which the same thing is done over and over, it may be advisable to
manually peform a minor collection once the duty cycle has ended. Example duty cycles include:
The rendering cycle of a single game frame.
The whole interaction with a given app dialog (opening, filling, closing)
A group of network requests to refresh/sync app data.
Major Collections
Major collections may be manually performed by calling GC.Collect() or GC.Collect(GC.MaxGeneration) .
They should be performed rarely, and may have a pause time of a second on an Android-style device when
collecting a 512MB heap.
Major collections should only be manually invoked, if ever:
At the end of lengthy duty cycles and when a long pause won't present a problem to the user.
Within an overridden Android.App.Activity.OnLowMemory() method.
Diagnostics
To track when global references are created and destroyed, you can set the debug.mono.log system property to
contain gref and/or gc.
Configuration
The Xamarin.Android garbage collector can be configured by setting the MONO_GC_PARAMS environment variable.
Environment variables may be set with a Build action of AndroidEnvironment.
The MONO_GC_PARAMS environment variable is a comma-separated list of the following parameters:
nursery-size= size : Sets the size of the nursery. The size is specified in bytes and must be a power of two.
The suffixes k , m and g can be used to specify kilo-, mega- and gigabytes, respectively. The nursery is
the first generation (of two). A larger nursery will usually speed up the program but will obviously use more
memory. The default nursery size 512 kb.
soft-heap-limit= size : The target maximum managed memory consumption for the app. When memory
use is below the specified value, the GC is optimized for execution time (fewer collections). Above this limit,
the GC is optimized for memory usage (more collections).
evacuation-threshold = threshold : Sets the evacuation threshold in percent. The value must be an integer
in the range 0 to 100. The default is 66. If the sweep phase of the collection finds that the occupancy of a
specific heap block type is less than this percentage, it will do a copying collection for that block type in the
next major collection, thereby restoring occupancy to close to 100 percent. A value of 0 turns evacuation off.
bridge-implementation = bridge implementation : This will set the GC Bridge option to help address GC
performance issues. There are three possible values: old , new , tarjan.
bridge-require-precise-merge: The Tarjan bridge contains an optimization which may, on rare occasions,
cause an object to be collected one GC after it first becomes garbage. Including this option disables that
optimization, making GCs more predictable but potentially slower.
For example, to configure the GC to have a heap size limit of 128MB, add a new file to your Project with a Build
action of AndroidEnvironment with the contents:
MONO_GC_PARAMS=soft-heap-limit=128m
Limitations
5/2/2018 • 3 minutes to read • Edit Online
Since applications on Android require generating Java proxy types during the build process, it is not possible to
generate all code at runtime.
These are the Xamarin.Android limitations compared to desktop Mono:
[Service]
class MyIntentService : IntentService {
public MyIntentService (): base ("value")
{
}
}
While this looks perfectly logical, the resulting Android callable wrapper in Release builds will not contain a default
constructor. Consequently, if you attempt to start this service (e.g. Context.StartService ), it will fail:
E/AndroidRuntime(31766): FATAL EXCEPTION: main
E/AndroidRuntime(31766): java.lang.RuntimeException: Unable to instantiate service example.MyIntentService:
java.lang.InstantiationException: can't instantiate class example.MyIntentService; no empty constructor
E/AndroidRuntime(31766): at android.app.ActivityThread.handleCreateService(ActivityThread.java:2347)
E/AndroidRuntime(31766): at android.app.ActivityThread.access$1600(ActivityThread.java:130)
E/AndroidRuntime(31766): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1277)
E/AndroidRuntime(31766): at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime(31766): at android.os.Looper.loop(Looper.java:137)
E/AndroidRuntime(31766): at android.app.ActivityThread.main(ActivityThread.java:4745)
E/AndroidRuntime(31766): at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(31766): at java.lang.reflect.Method.invoke(Method.java:511)
E/AndroidRuntime(31766): at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
E/AndroidRuntime(31766): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
E/AndroidRuntime(31766): at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime(31766): Caused by: java.lang.InstantiationException: can't instantiate class
example.MyIntentService; no empty constructor
E/AndroidRuntime(31766): at java.lang.Class.newInstanceImpl(Native Method)
E/AndroidRuntime(31766): at java.lang.Class.newInstance(Class.java:1319)
E/AndroidRuntime(31766): at android.app.ActivityThread.handleCreateService(ActivityThread.java:2344)
E/AndroidRuntime(31766): ... 10 more
The workaround is to declare a default constructor, adorn it with the ExportAttribute , and set the
ExportAttribute.SuperStringArgument :
[Service]
class MyIntentService : IntentService {
[Export (SuperArgumentsString = "\"value\"")]
public MyIntentService (): base("value")
{
}
// ...
}
Generic C# classes
Generic C# classes are only partially supported. The following limitations exist:
Generic types may not use [Export] or [ExportField ]. Attempting to do so will generate an XA4207 error.
Instances of Generic types must not be created from Java code. They can only safely be created from
managed code:
Related Links
Android Callable Wrappers
Working with JNI
ExportAttribute
SuperString
RegisterAttribute
Troubleshooting
5/2/2018 • 2 minutes to read • Edit Online
Troubleshooting Tips
Troubleshooting tips and tricks.
System properties are read during process startup, and thus must be either set before the application is launched
or the application must be restarted after the system properties are changed.
Xamarin.Android System Properties
Xamarin.Android supports the following system properties:
debug.mono.debug: If a non-empty string, this is equivalent to *mono-debug* .
debug.mono.env: A pipe-separated ('|') list of environment variables to export during application startup,
before mono has been initialized. This allows setting environment variables that control mono logging.
Note: Since the value is '|'-separated, the value must have an extra level of quoting, as the `adb shell`
command will remove a set of quotes.
Note: Android system property values can be no longer than 92 characters in length.
Example:
debug.mono.log: A comma-separated (',') list of components that should print additional messages to the
Android Debug Log. By default, nothing is set. Components include:
all: Print all messages
gc: Print GC -related messages.
gref: Print (weak, global) reference allocation and deallocation messages.
lref: Print local reference allocation and deallocation messages.
Note: these are extremely verbose. Do not enable unless you really need to.
debug.mono.trace: Allows setting the mono --trace =PROPERTY_VALUE setting.
GC Messages
GC component messages can be viewed by setting the debug.mono.log system property to a value that contains
gc.
GC messages are generated whenever the GC executes and provides information about how much work the GC
did:
Additional GC information such as timing information can be generated by setting the MONO_LOG_LEVEL
environment variable to debug :
This will result in (lots of ) additional Mono messages, including these three of consequence:
D/Mono (15723): GC_BRIDGE num-objects 1 num_hash_entries 81226 sccs size 81223 init 0.00ms df1 285.36ms sort
38.56ms dfs2 50.04ms setup-cb 9.95ms free-data 106.54ms user-cb 20.12ms clenanup 0.05ms links
5523436/5523436/5523096/1 dfs passes 1104 6883/11046605
D/Mono (15723): GC_MINOR: (Nursery full) pause 2.01ms, total 287.45ms, bridge 225.60 promoted 0K major 325184K
los 1816K
D/Mono ( 2073): GC_MAJOR: (user request) pause 2.17ms, total 2.47ms, bridge 28.77 major 576K/576K los 0K/16K
In the message, num-objects is the number of bridge objects this pass is considering, and
GC_BRIDGE
num_hash_entries is the number of objects processed during this invocation of the bridge code.
In the GC_MINOR and GC_MAJOR messages, total is the amount of time while the world is paused (no threads are
executing), while bridge is the amount of time taken in the bridge processing code (which deals with the Java
VM ). The world is not paused while bridge processing occurs.
In general, the larger the value of num_hash_entries , the more time that the bridge collections will take, and the
larger the total time spent collecting will be.
Xamarin.Android uses Android global references to provide mappings between Java instances and the associated
managed instances, as when invoking a Java method a Java instance needs to be provided to Java.
Unfortunately, Android emulators only allow 2000 global references to exist at a time. Hardware has a much
higher limit of 52000 global references. The lower limit can be problematic when running applications on the
emulator, so knowing where the instance came from can be very useful.
Note: the global reference count is internal to Xamarin.Android, and does not (and cannot) include global
references taken out by other native libraries loaded into the process. Use the global reference count as an
estimate.
I/monodroid-gref(12405): +g+ grefc 108 gwrefc 0 obj-handle 0x40517468/L -> new-handle 0x40517468/L from at
Java.Lang.Object.RegisterInstance(IJavaObject instance, IntPtr value, JniHandleOwnership transfer)
I/monodroid-gref(12405): at Java.Lang.Object.SetHandle(IntPtr value, JniHandleOwnership transfer)
I/monodroid-gref(12405): at Java.Lang.Object..ctor(IntPtr handle, JniHandleOwnership transfer)
I/monodroid-gref(12405): at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler, Boolean
removable)
I/monodroid-gref(12405): at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler)
I/monodroid-gref(12405): at Android.App.Activity.RunOnUiThread(System.Action action)
I/monodroid-gref(12405): at Mono.Samples.Hello.HelloActivity.UseLotsOfMemory(Android.Widget.TextView
textview)
I/monodroid-gref(12405): at Mono.Samples.Hello.HelloActivity.<OnCreate>m__3(System.Object o)
I/monodroid-gref(12405): handle 0x40517468; key_handle 0x40517468: Java Type:
`mono/java/lang/RunnableImplementor`; MCW type: `Java.Lang.Thread+RunnableImplementor`
I/monodroid-gref(12405): Disposing handle 0x40517468
I/monodroid-gref(12405): -g- grefc 107 gwrefc 0 handle 0x40517468/L from at
Java.Lang.Object.Dispose(System.Object instance, IntPtr handle, IntPtr key_handle, JObjectRefType handle_type)
I/monodroid-gref(12405): at Java.Lang.Object.Dispose()
I/monodroid-gref(12405): at Java.Lang.Thread+RunnableImplementor.Run()
I/monodroid-gref(12405): at Java.Lang.IRunnableInvoker.n_Run(IntPtr jnienv, IntPtr native__this)
I/monodroid-gref(12405): at System.Object.c200fe6f-ac33-441b-a3a0-47659e3f6750(IntPtr , IntPtr )
I/monodroid-gref(27679): +w+ grefc 1916 gwrefc 296 obj-handle 0x406b2b98/G -> new-handle 0xde68f4bf/W from
take_weak_global_ref_jni
I/monodroid-gref(27679): -w- grefc 1915 gwrefc 294 handle 0xde691aaf/W from take_global_ref_jni
A GC is being performed...
I/monodroid-gref(27679): +w+ grefc 1953 gwrefc 259 obj-handle 0x4066df10/G -> new-handle 0xde68f95f/W from
take_weak_global_ref_jni
I/monodroid-gref(27679): -g- grefc 1952 gwrefc 259 handle 0x4066df10/G from take_weak_global_ref_jni
There is one "interesting" wrinkle here: on targets running Android prior to 4.0, the gref value is equal to the
address of the Java object in the Android runtime's memory. (That is, the GC is a non-moving, conservative,
collector, and it's handing out direct references to those objects.) Thus after a +g+, +w+, -g-, +g+, -w - sequence,
the resulting gref will have the same value as the original gref value. This makes grepping through logs fairly
straightforward.
Android 4.0, however, has a moving collector and no longer hands out direct references to Android runtime VM
objects. Consequently, after a +g+, +w+, -g-, +g+, -w - sequence, the gref value will be different. If the object
survives multiple GCs, it will go by several gref values, making it harder to determine where an instance was
actually allocated from.
Querying Programmatically
You can query both the GREF and WREF counts by querying the JniRuntime object.
Java.Interop.JniRuntime.CurrentRuntime.GlobalReferenceCount - Global Reference Count
Java.Interop.JniRuntime.CurrentRuntime.WeakGlobalReferenceCount - Weak Reference Count
Offline Activation
If you're unable to activate Xamarin.Android on Windows, or unable to install the full version of Xamarin.Android
on Mac OS X, please see the Offline Activation page.
adb devices
If your device isn't present, then you need to restart the Android Debug Bridge server so that your device can be
found:
adb kill-server
adb start-server
HTC Sync software may prevent adb start-server from working properly. If the adb start-server command
doesn't print out which port it's starting on, please exit the HTC Sync software and try restarting the adb server.
Ensure you use the correct simulator name, i.e. the name you used when configuring the simulator.
E/PackageManager( 146): Package [PackageName] signatures do not match the previously installed version;
ignoring!
To fix this error, completely remove the application from your device before re-installing.
To work around this issue, fully uninstall the Android package, either by installing the app from the Android
target's GUI, or using adb :
DO NOT USE adb uninstall -k , as this will preserve application data, and thus preserve the conflicting UID on
the target device.
The output will contain the primary (and optional secondary) ABIs.
The problem is that Xamarin.Android incorrectly marshals nested generic types. The
List<IDictionary<string, object>> is being marshaled to a java.lang.ArrrayList, but the ArrayList is containing
mono.android.runtime.JavaObject instances (which reference the Dictionary<string, object> instances) instead of
something that implements java.util.Map, resulting in the following exception:
The workaround is to use the provided Java Collection types instead of the System.Collections.Generic types for
the “inner” types. This will result in appropriate Java types when marshaling the instances. (The following code is
more complicated than necessary in order to reduce gref lifetimes. It can be simplified to altering the original code
via s/List/JavaList/g and s/Dictionary/JavaDictionary/g if gref lifetimes aren't a worry.)
Unexpected NullReferenceExceptions
Occasionally the Android Debug Log will mention NullReferenceExceptions that “cannot happen,” or come from
Mono for Android runtime code shortly before the app dies:
E/mono(15202): Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of
an object
E/mono(15202): at Java.Lang.Object.GetObject (IntPtr handle, System.Type type, Boolean owned)
E/mono(15202): at Java.Lang.Object._GetObject[IOnTouchListener] (IntPtr handle, Boolean owned)
E/mono(15202): at Java.Lang.Object.GetObject[IOnTouchListener] (IntPtr handle, Boolean owned)
E/mono(15202): at
Android.Views.View+IOnTouchListenerAdapter.n_OnTouch_Landroid_view_View_Landroid_view_MotionEvent_(IntPtr
jnienv, IntPtr native__this, IntPtr native_v, IntPtr native_e)
E/mono(15202): at (wrapper dynamic-method) object:b039cbb0-15e9-4f47-87ce-442060701362
(intptr,intptr,intptr,intptr)
or
This can happen when the Android runtime decides to abort the process, which can happen for any number of
reasons, including hitting the target's GREF limit or doing something “wrong” with JNI.
To see if this is the case, check the Android Debug Log for a message from your process similar to:
When you reach the GREF limit, a message such as the following is printed:
D/dalvikvm( 602): GREF has increased to 2001
W/dalvikvm( 602): Last 10 entries in JNI global reference table:
W/dalvikvm( 602): 1991: 0x4057eff8 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm( 602): 1992: 0x4057f010 cls=Landroid/graphics/Point; (28 bytes)
W/dalvikvm( 602): 1993: 0x40698e70 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm( 602): 1994: 0x40698e88 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm( 602): 1995: 0x40698ea0 cls=Landroid/graphics/Point; (28 bytes)
W/dalvikvm( 602): 1996: 0x406981f0 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm( 602): 1997: 0x40698208 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm( 602): 1998: 0x40698220 cls=Landroid/graphics/Point; (28 bytes)
W/dalvikvm( 602): 1999: 0x406956a8 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm( 602): 2000: 0x406956c0 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm( 602): JNI global reference table summary (2001 entries):
W/dalvikvm( 602): 51 of Ljava/lang/Class; 164B (41 unique)
W/dalvikvm( 602): 46 of Ljava/lang/Class; 188B (17 unique)
W/dalvikvm( 602): 6 of Ljava/lang/Class; 212B (6 unique)
W/dalvikvm( 602): 11 of Ljava/lang/Class; 236B (7 unique)
W/dalvikvm( 602): 3 of Ljava/lang/Class; 260B (3 unique)
W/dalvikvm( 602): 4 of Ljava/lang/Class; 284B (2 unique)
W/dalvikvm( 602): 8 of Ljava/lang/Class; 308B (6 unique)
W/dalvikvm( 602): 1 of Ljava/lang/Class; 316B
W/dalvikvm( 602): 4 of Ljava/lang/Class; 332B (3 unique)
W/dalvikvm( 602): 1 of Ljava/lang/Class; 356B
W/dalvikvm( 602): 2 of Ljava/lang/Class; 380B (1 unique)
W/dalvikvm( 602): 1 of Ljava/lang/Class; 428B
W/dalvikvm( 602): 1 of Ljava/lang/Class; 452B
W/dalvikvm( 602): 1 of Ljava/lang/Class; 476B
W/dalvikvm( 602): 2 of Ljava/lang/Class; 500B (1 unique)
W/dalvikvm( 602): 1 of Ljava/lang/Class; 548B
W/dalvikvm( 602): 1 of Ljava/lang/Class; 572B
W/dalvikvm( 602): 2 of Ljava/lang/Class; 596B (2 unique)
W/dalvikvm( 602): 1 of Ljava/lang/Class; 692B
W/dalvikvm( 602): 1 of Ljava/lang/Class; 956B
W/dalvikvm( 602): 1 of Ljava/lang/Class; 1004B
W/dalvikvm( 602): 1 of Ljava/lang/Class; 1148B
W/dalvikvm( 602): 2 of Ljava/lang/Class; 1172B (1 unique)
W/dalvikvm( 602): 1 of Ljava/lang/Class; 1316B
W/dalvikvm( 602): 1 of Ljava/lang/Class; 3428B
W/dalvikvm( 602): 1 of Ljava/lang/Class; 3452B
W/dalvikvm( 602): 1 of Ljava/lang/String; 28B
W/dalvikvm( 602): 2 of Ldalvik/system/VMRuntime; 12B (1 unique)
W/dalvikvm( 602): 10 of Ljava/lang/ref/WeakReference; 28B (10 unique)
W/dalvikvm( 602): 1 of Ldalvik/system/PathClassLoader; 44B
W/dalvikvm( 602): 1553 of Landroid/graphics/Point; 20B (1553 unique)
W/dalvikvm( 602): 261 of Landroid/graphics/Point; 28B (261 unique)
W/dalvikvm( 602): 1 of Landroid/view/MotionEvent; 100B
W/dalvikvm( 602): 1 of Landroid/app/ActivityThread$ApplicationThread; 28B
W/dalvikvm( 602): 1 of Landroid/content/ContentProvider$Transport; 28B
W/dalvikvm( 602): 1 of Landroid/view/Surface$CompatibleCanvas; 44B
W/dalvikvm( 602): 1 of Landroid/view/inputmethod/InputMethodManager$ControlledInputConnectionWrapper; 36B
W/dalvikvm( 602): 1 of Landroid/view/ViewRoot$1; 12B
W/dalvikvm( 602): 1 of Landroid/view/ViewRoot$W; 28B
W/dalvikvm( 602): 1 of Landroid/view/inputmethod/InputMethodManager$1; 28B
W/dalvikvm( 602): 1 of Landroid/view/accessibility/AccessibilityManager$1; 28B
W/dalvikvm( 602): 1 of Landroid/widget/LinearLayout$LayoutParams; 44B
W/dalvikvm( 602): 1 of Landroid/widget/LinearLayout; 332B
W/dalvikvm( 602): 2 of Lorg/apache/harmony/xnet/provider/jsse/TrustManagerImpl; 28B (1 unique)
W/dalvikvm( 602): 1 of Landroid/view/SurfaceView$MyWindow; 36B
W/dalvikvm( 602): 1 of Ltouchtest/RenderThread; 92B
W/dalvikvm( 602): 1 of Landroid/view/SurfaceView$3; 12B
W/dalvikvm( 602): 1 of Ltouchtest/DrawingView; 412B
W/dalvikvm( 602): 1 of Ltouchtest/Activity1; 180B
W/dalvikvm( 602): Memory held directly by tracked refs is 75624 bytes
E/dalvikvm( 602): Excessive JNI global references (2001)
E/dalvikvm( 602): VM aborting
In the above example (which, incidentally, comes from bug 685215) the problem is that too many
Android.Graphics.Point instances are being created; see comment #2 for a list of fixes for this particular bug.
Typically, a useful solution is to find which type has too many instances allocated – Android.Graphics.Point in the
above dump – then find where they're created in your source code and dispose of them appropriately (so that their
Java-object lifetime is shortened). This is not always appropriate (#685215 is multithreaded, so the trivial solution
avoids the Dispose call), but it's the first thing to consider.
You can enable GREF Logging to see when GREFs are created and how many exist.
General Questions
How do I automate an Android NUnit Test project?
This guide covers steps for setting up an Android NUnit test project, not a Xamarin.UITest project. Xamarin.UITest
guides can be found here.
How do I enable Intellisense in Android .axml files?
This guide describes how to activate Visual Studio's Intellisense for Android .axml files.
Why can't my Android release build connect to the Internet?
The most common cause of this issue is that the INTERNET permission is automatically included in a debug
build, but must be set manually for a release build. This guide describes how to enable the permission on release
builds.
Smarter Xamarin Android Support v4 / v13 NuGet Packages
Support-v4 and Support-v13 can not be used together in the same app, that is, they are mutually exclusive. This is
because Support-v13 actually contains all of the types and implementation of Support-v4 . If you try and reference
both in the same project you will encounter duplicate type errors.
How do I resolve a PathTooLongException Error?
This article explains how to resolve a PathTooLongException error that may occur while building a
Xamarin.Android project.
Deprecated
NOTE
The articles below apply to issues that have been resolved in recent versions of Xamarin. However, if the issue occurs on the
latest version of the software, please file a new bug with your full versioning information and full build log output.
Installing the Android SDK doesn't automatically include all the minimum required packages for developing. While
individual developer needs vary, the following packages will generally be required for developing with
Xamarin.Android:
Tools
Install the latest tools from the Tools folder in the SDK manager:
Android SDK Tools
Android SDK Platform-Tools
Android SDK Build-Tools
Android Platform(s)
Install the "SDK Platform" for the Android versions you've set as minimum & target.
Examples:
Target API 23
Minimum API 23
Only need to install SDK Platform for API 23
Target API 23
Minimum API 15
Need to install SDK Platforms for API 15 and 23. Note that you do not need to install the API levels between the
minimum and target (even if you are backporting to those API levels).
System Images
These are only required if you want to use the out-of-the-box Android emulators from Google. For more
information, see Android Emulator Setup
Extras
The Android SDK Extras are usually not required; but it is useful to be aware of them since they may be required
depending on your use case.
Further Reading
The following guide covers these options and goes into more detail about the different packages the SDK manager
has avaliable: Android SDK Manager Setup Guide
Where can I set my Android SDK locations?
4/12/2018 • 2 minutes to read • Edit Online
Visual Studio
Visual Studio for Mac
In Visual Studio, navigate to Tools > Options > Xamarin > Android Settings to view and set the Android SDK
location:
This article illustrates how to update the Java Development Kit (JDK ) version on Windows and Mac.
Overview
Xamarin.Android uses the Java Development Kit (JDK) to integrate with the Android SDK for building Android
apps and running the Android designer. The latest versions of the Android SDK (API 24 and higher) require JDK 8
(1.8). If you have not yet updated to JDK 8, follow these steps to install and enable it:
Visual Studio
Visual Studio for Mac
1. Download JDK 8 (1.8) from the Oracle website:
2. Pick the 64-bit version to allow rendering of custom controls in the Xamarin Android designer:
3. Run the .exe and install the Development Tools:
4. Open Visual Studio and update the Java Development Kit Location to point to the new JDK under Tools
> Options > Xamarin > Android Settings > Java Development Kit Location > Change:
This article explains how to resolve Java Development Kit (JDK ) 9 errors in Xamarin.Android.
Overview
Xamarin.Android uses the Java Development Kit (JDK) to integrate with the Android SDK for building Android
apps and running the Android designer. The latest versions of the Android SDK (API 24 and higher) require JDK 8
(1.8). Because the Android SDK tools available from Google are not yet compatible with JDK 9,
Xamarin.Android does not work with JDK 9.
JDK 9 Errors
If you try to build a Xamarin.Android project with JDK 9 installed, you will get an explicit error indicating that JDK
9 is not supported.
Building with JDK Version `9.0.4` is not supported. Please install JDK version `1.8.0`. See
https://aka.ms/xamarin/jdk9-errors
To resolve these errors, you must install JDK 8 (1.8) as explained in How do I update the Java Development Kit
(JDK) version?.
java -version
If JDK 9 is installed, you must install Java JDK 8 (1.8). For information about how to install JDK 8, see How do I
update the Java Development Kit (JDK) version?
Note that you do not have to uninstall JDK 9; however, you must ensure that Xamarin is using JDK 8 rather than
JDK 9. In Visual Studio, click Tools > Options > Xamarin > Android Settings. If Java Development Kit
Location is not set to a JDK 8 location (such as C:\Program Files\Java\jdk1.8.0_111), click Change and set it to
the location where JDK 8 is installed. In Visual Studio for Mac, navigate to Preferences > Projects > SDK
Locations > Android > Java SDK (JDK) and click Browse to update this path.
Example output:
Download android_m2repository.zip from Google using the URL returned from ildasm. Alternately, you can
check which version of the Android Support Repository you currently have installed in the Android SDK Manager:
If the version matches the one you need for the NuGet package, then you don't have to download anything new.
You can instead re-zip the existing m2repository directory that is located under extras\android in the SDK Path
(as shown the top of the Android SDK Manager window ).
Calculate the MD5 hash of the URL returned from ildasm. Format the resulting string to use all uppercase letters
and no spaces. For example, adjust the $url variable as needed and then run the following 2 lines (based on the
original C# code from Xamarin.Android) in PowerShell:
$url = "https://dl-ssl.google.com/android/repository/android_m2repository_r32.zip"
(([System.Security.Cryptography.MD5]::Create()).ComputeHash([System.Text.Encoding]::UTF8.GetBytes($url)) | %{
$_.ToString("X02") }) -join ""
Example output:
F16A3455987DBAE5783F058F19F7FCDF
Copy android_m2repository.zip into the %LOCALAPPDATA%\Xamarin\zips\ folder. Rename the file to use
the MD5 hash from the previous MD5 hash calculating step. For example:
%LOCALAPPDATA%\Xamarin\zips\F16A3455987DBAE5783F058F19F7FCDF.zip
(Optional) Unzip the file into %LOCALAPPDATA%\Xamarin\Xamarin.Android.Support.v4\23.4.0.0\content\
(creating a content\m2repository subdirectory). If you skip this step, then the first build that uses the library will
take a little longer because it will need to complete this step. The version number for the subdirectory (23.4.0.0 in
this example) is not quite the same as the NuGet package version. You can use ildasm to find the correct version
number:
Example output:
Additional references
Bug 43245 – Inaccurate "Download failed. Please download {0} and put it to the {1} directory." and "Please
install package: '{0}' available in SDK installer" error messages related to Xamarin.Android.Support packages
Next Steps
This document discusses the current behavior as of August 2016. The technique described in this document is not
part of the stable testing suite for Xamarin, so it could break in the future.
For further assistance, to contact us, or if this issue remains even after utilizing the above information, please see
What support options are available for Xamarin? for information on contact options, suggestions, as well as how to
file a new bug if needed.
How do I install Google Play Services in an emulator?
4/12/2018 • 2 minutes to read • Edit Online
This Stack Overflow post covers how to install Google Play Services in Visual Studio's Android Emulator:
http://stackoverflow.com/questions/31550628/visual-studio-emulator-for-android-install-gapps-google-play-
services
Instructions to install the Google Play Services in the deprecated Xamarin Android Player can be found here:
https://university.xamarin.com/resources/how -to-install-google-play-on-android-emulator
What USB drivers do I need to debug Android on
Windows?
6/27/2018 • 2 minutes to read • Edit Online
Alternatives
Depending on the manfacturer, it can be difficult to track down the exact USB driver needed. Some alternatives for
testing Android apps developed in Windows including using an Android emulator or using external testing
services. Some of these include:
App Center Test - Cloud Testing services run on hundreds of real Android devices.
Visual Studio Emulator for Android
Debugging on the Android Emulator
Is it possible to connect to Android emulators
running on a Mac from a Windows VM?
6/25/2018 • 3 minutes to read • Edit Online
To connect to the Android Emulator running on a Mac from a Windows virtual machine, use the following steps:
1. Start the emulator on the Mac.
2. Kill the adb server on the Mac:
adb kill-server
3. Note that the emulator is listening on 2 TCP ports on the loopback network interface:
emulator6 94105 macuser 20u IPv4 0xa8dacfb1d4a1b51f 0t0 TCP localhost:5555 (LISTEN)
emulator6 94105 macuser 21u IPv4 0xa8dacfb1d845a51f 0t0 TCP localhost:5554 (LISTEN)
The odd-numbered port is the one used to connect to adb . See also
http://developer.android.com/tools/devices/emulator.html#emulatornetworking.
4. Option 1: Use nc to forward inbound TCP packets received externally on port 5555 (or any other port you
like) to the odd-numbered port on the loopback interface (127.0.0.1 5555 in this example), and to forward
the outbound packets back the other way:
cd /tmp
mkfifo backpipe
nc -kl 5555 0<backpipe | nc 127.0.0.1 5555 > backpipe
As long as the nc commands stay running in a Terminal window, the packets will be forwarded as
expected. You can type Control-C in the Terminal window to quit the nc commands once you're done using
the emulator.
(Option 1 is usually easier than Option 2, especially if System Preferences > Security & Privacy >
Firewall is switched on.)
Option 2: Use pfctl to redirect TCP packets from port 5555 (or any other port you like) on the Shared
Networking interface to the odd-numbered port on the loopback interface ( 127.0.0.1:5555 in this example):
sed '/rdr-anchor/a rdr pass on vmnet8 inet proto tcp from any to any port 5555 -> 127.0.0.1 port 5555'
/etc/pf.conf | sudo pfctl -ef -
This command sets up port forwarding using the pf packet filter system service. The line breaks are
important. Be sure to keep them intact when copy-pasting. You will also need to adjust the interface name
from vmnet8 if you're using Parallels. vmnet8 is the name of the special NAT device for the Shared
Networking mode in VMWare Fusion. The appropriate network interface in Parallels is likely vnic0.
5. Connect to the emulator from the Windows machine:
C:\> adb connect ip-address-of-the-mac:5555
Replace "ip-address-of-the-mac" with the IP address of the Mac, for example as listed by
ifconfig vmnet8 | grep 'inet ' . If needed, replace 5555 with the other port you like from step 4. ( Note:
one way to get command-line access to adb is via Tools > Android > Android Adb Command Prompt
in Visual Studio.)
Alternate technique using ssh
If you have enabled Remote Login on the Mac, then you can use ssh port forwarding to connect to the emulator.
1. Install an SSH client on Windows. One option is to install Git for Windows. The ssh command will then be
available in the Git Bash command prompt.
2. Follow steps 1-3 from above to start the emulator, kill the adb server on the Mac, and identify the emulator
ports.
3. Run ssh on Windows to set up two-way port forwarding between a local port on Windows (
localhost:15555 in this example) and the odd-numbered emulator port on the Mac's loopback interface (
127.0.0.1:5555 in this example):
Replace mac-username with your Mac username as listed by whoami . Replace ip-address-of-the-mac with
the IP address of the Mac.
4. Connect to the emulator using the local port on Windows:
(Note: one easy way to get command-line access to adb is via Tools > Android > Android Adb
Command Prompt in Visual Studio.)
A small caution: if you use port 5555 for the local port, adb will think that the emulator is running locally on
Windows. This doesn't cause any trouble in Visual Studio, but in Visual Studio for Mac it causes the app to exit
immediately after launch.
Alternate technique using adb -H is not yet supported
In theory, another approach would be to use adb 's built-in capability to connect to an adb server running on a
remote machine (see for example http://stackoverflow.com/a/18551325). But the Xamarin.Android IDE extensions
do not currently provide a way to configure that option.
Contact information
This document discusses the current behavior as of March, 2016. The technique described in this document is not
part of the stable testing suite for Xamarin, so it could break in the future.
If you notice that the technique no longer works, or if you notice any other mistakes in the document, feel free to
add to the discussion on the following forum thread: http://forums.xamarin.com/discussion/33702/android-
emulator-from-host-device-inside-windows-vm. Thanks!
How do I automate an Android NUnit Test project?
4/12/2018 • 2 minutes to read • Edit Online
NOTE
This guide explains how to automate an Android NUnit test project, not a Xamarin.UITest project. Xamarin.UITest guides can
be found here.
When you create a Unit Test App (Android) project in Visual Studio (or Android Unit Test project in Visual
Studio for Mac), this project will not automatically run your tests by default. To run NUnit tests on a target device,
you can create an Android.App.Instrumentation subclass that is started by using the following command:
using System;
using System.Reflection;
using Android.App;
using Android.Content;
using Android.Runtime;
using Xamarin.Android.NUnitLite;
namespace App.Tests {
[Instrumentation(Name="app.tests.TestInstrumentation")]
public class TestInstrumentation : TestSuiteInstrumentation {
4. Use the following command to run the unit tests. Replace PACKAGE_NAME with the app's package name (the
package name can be found in the app's /manifest/@package attribute located in AndroidManifest.xml):
5. Optionally, you can modify the .csproj file to add the RunTests MSBuild target. This makes it possible to
invoke the unit tests with a command like the following:
(Note that using this new target is not required; the earlier adb command can be used instead of msbuild .)
For more information about using the adb shell am instrument command to run unit tests, see the Android
Developer Running tests with ADB topic.
NOTE
With the Xamarin.Android 5.0 release, the default package names for Android Callable Wrappers will be based on the
MD5SUM of the assembly-qualified name of the type being exported. This allows the same fully-qualified name to be
provided from two different assemblies and not get a packaging error. So make sure that you use the Name property on the
Instrumentation attribute to generate a readable ACW/class name.
The ACW name must be used in the adb command above. Renaming/refactoring the C# class will thus require
modifying the RunTests command to use the correct ACW name.
How do I enable Intellisense in Android .axml files?
4/12/2018 • 2 minutes to read • Edit Online
Android Intellisense in Visual Studio needs two XML Schema files to work appropriately. To find these files, go to
this folder:
C:\Program Files (x86)\Xamarin Studio\AddIns\MonoDevelop.MonoDroid\schemas *
*(Previously: C:\Program Files (x86)\MSBuild\Xamarin\Android )
Inside you will find two .xsd files:
1. android-layout-xml.xsd
2. schemas.android.com.apk.res.android.xsd
Visual Studio keeps all of the XML Schemas inside the respective folder:
C:\Program Files (x86)\Microsoft Visual Studio 12.0\Xml\Schemas
You can choose to move these two .xsd files to the location above, or simply just add these schemas within Visual
Studio. You can then "Add" these schemas inside Visual Studio via the XML > Schemas > Add dialog.
Why can't my Android release build connect to the
Internet?
4/12/2018 • 2 minutes to read • Edit Online
Cause
The most common cause of this issue is that the INTERNET permission is automatically included in a debug
build, but must be set manually for a release build. This is because the Internet permission is used to allow a
debugger to attach to the process, as described for "DebugSymbols" here.
Fix
To resolve the issue, you can require the Internet permission in the Android Manifest. This can be done either
through the manifest editor or the manifest's sourcecode:
Fix in Editor: In your Android project, go to Properties -> AndroidManifest.xml -> Required
Permissions and check Internet
Fix in Sourcecode: Open the AndroidManifest in a source editor and add the permission tag inside the
<Manifest> tags:
<Manifest>
...
<uses-permission android:name="android.permission.INTERNET" />
</Manifest>
Smarter Xamarin Android Support v4 / v13 NuGet
Packages
4/12/2018 • 2 minutes to read • Edit Online
NuGet Assistance
While a developer could manually add the correct references necessary, we are able to use NuGet to help choose
the right assembly (either the normal v4 binding or the type-forwarded v4 assembly) when the NuGet package is
installed.
So, the Xamarin.Android.Support.v4 NuGet package now contains the following logic:
If your app is targeting API Level 13 (Gingerbread 3.2) or higher:
NuGet will automatically be added as a dependency
Xamarin.Android.Support.v13
The type-forwarded Xamarin.Android.Support.v4.dll will be referenced in the project
If your app is targeting anything lower than API Level 13, you will get the normal Xamarin.Android.Support.v4.dll
binding referenced in your project.
Do I have to use Support-v13?
If your app is targeting API Level 13 or higher and you choose to use the Xamarin Android Support-v4 NuGet
package, then the Xamarin Android Support v13 NuGet package is a required dependency.
We feel the very minor increase in app size (the two .jar files differ by 17kb) is well worth the compatibility and
fewer headaches it results in.
If you are adamant about using Support-v4 in an app that targets API Level 13 or higher, you can always manually
download the .nupkg , extract it, and reference the assembly.
How do I resolve a PathTooLongException error?
5/29/2018 • 2 minutes to read • Edit Online
Cause
Generated path names in a Xamarin.Android project can be quite long. For example, a path like the following could
be generated during a build:
C:\Some\Directory\Solution\Project\obj\Debug\library_projects\Xamarin.Forms.Platform.Android\libr
ary_project_imports\assets
On Windows (where the maximum length for a path is 260 characters), a PathTooLongException could be
produced while building the project if a generated path exceeds the maximum length.
Fix
Beginning with Xamarin.Android 8.0, the UseShortFileNames MSBuild property can be set to circumvent this error.
When this property is set to True (the default is False ), the build process uses shorter path names to reduce the
likelihood of producing a PathTooLongException. For example, when UseShortFileNames is set to True , the
above path is shortened to path that is similar to the following:
C:\Some\Directory\Solution\Project\obj\Debug\lp\1\jl\assets
To set this property, add the following MSBuild property to the project .csproj file:
<PropertyGroup>
<UseShortFileNames>True</UseShortFileNames>
</PropertyGroup>
If setting this flag does not fix the PathTooLongException error, another approach is to specify a common
intermediate output root for projects in your solution by setting IntermediateOutputPath in the project .csproj file.
Try to use a relatively short path. For example:
<PropertyGroup>
<IntermediateOutputPath>C:\Projects\MyApp</IntermediateOutputPath>
</PropertyGroup>
For more information about setting build properties, see Build Process.
What version of Xamarin.Android added Lollipop
support?
4/12/2018 • 2 minutes to read • Edit Online
Note: This guide was originally written for the Android L preview.
Xamarin.Android 4.17 added Android L Preview support.
Xamarin.Android 4.20 added Android Lollipop support.
Xamarin only actively supports the current stable release of the Xamarin tools. The information below is provided
"as-is" for older versions of the tools. For the latest information on Xamarin releases, please check here.
This message means that the Android SDK platform for API Level 21 is not installed. Either install it in the Android
SDK Manager (Tools > Open Android SDK Manager...), or change your Xamarin.Android project to target an API
version that is installed.
There are a few workarounds for this issue:
1. Change your project so that it targets API 19 or lower.
2. Rename your android-21 folder from android-21 to android-L. (At best, this should only be used as a
temporary fix, and it might not work very well at all.)
%LOCALAPPDATA%\Android\android-sdk\platforms\android-21
3. Temporarily downgrade back to the Android API Level 21 "L" preview [1]:
a. Delete the %LOCALAPPDATA%\Android\android-sdk\platforms\android-21
b. Extract [1] into C:\Users\\AppData\Local\Android\android-sdk\platforms to create an android-L
folder.
[1] - https://dl-ssl.google.com/android/repository/android-L_r04.zip
Android.Support.v7.AppCompat - No resource found
that matches the given name: attr
'android:actionModeShareDrawable'
4/12/2018 • 2 minutes to read • Edit Online
1. Make sure you download the latest extras as well as the Android 5.0 (API 21) SDK via the Android SDK
Manager.
2. Ensure that you are compiling your application with compileSdkVersion set to 21. You can optionally set the
targetSdkVersion to 21 as well.
3. If you require a previous version such as API 19, please download the respective version found on the
Nuget page:
https://www.nuget.org/packages/Xamarin.Android.Support.v7.AppCompat/
Note: If you manually install this via Package Manager Console, make sure you also install the same version of
Xamarin.Android.Support.v4
https://www.nuget.org/packages/Xamarin.Android.Support.v4/
Stack Overflow Reference: http://stackoverflow.com/questions/26431676/appcompat-v721-0-0-no-resource-
found-that-matches-the-given-name-attr-andro
See Also
Which Android SDK packages should I install?
Adjusting Java memory parameters for the Android
designer
6/4/2018 • 2 minutes to read • Edit Online
The default memory parameters that are used when starting the java process for the Android designer might be
incompatible with some system configurations.
Starting with Xamarin Studio 5.7.2.7 (and later, Visual Studio for Mac) and Visual Studio Tools for Xamarin 3.9.344,
these settings can be customized on a per-project basis.
NOTE
This issue has been resolved in Xamarin Studio 5.1.4 and later versions. However, if the issue occurs in Visual Studio for Mac,
please file a new bug with your full versioning information and full build log output.
A bug in Xamarin.Studio 5.1 previously corrupted .csproj files by partially or completely deleting the xml code in
the .csproj file. This would cause important parts of the Android build system (such as updating the Android
Resource.designer.cs) to fail. As of the 5.1.4 stable release on July 15th, this bug has been fixed; but in many cases
the project file has to be repaired manually, as described below.
In some cases, you may get errors while installing Android support libraries. This guide provides workarounds for
some common errors.
Overview
While building a Xamarin.Android app project, you may get build errors when Visual Studio or Visual Studio for
Mac attempt to download and install dependency libraries. Many of these errors are caused by network
connectivity issues, file corruption, or versioning problems. This guide describes the most common support library
installation errors and provides the steps to work around these issues and get your app project building again.
This example is for android_m2repository_r16, but you may see this same error message for a different version
such as android_m2repository_r18 or android_m2repository_r25.
Automatic Recovery from m2repository Errors
Often, this issue can be remedied by deleting the problematic library and rebuilding according to these steps:
1. Navigate to the support library directory on your computer:
On Windows, support libraries are located at C:\Users\username\AppData\Local\Xamarin.
On Mac OS X, support libraries are located at /Users/username/.local/share/Xamarin.
2. Locate the library and version folder corresponding to the error message. For example, the library and
version folder for the above error message is located at Android.Support.v4\22.2.1:
3. Delete the contents of the version folder. Be sure to remove the .zip file as well as the content and
embedded subdirectories within this folder. For the example error message shown above, the files and
subdirectories shown in this screenshot (content, embedded, and android_m2repository_r16.zip) are to
be deleted:
Note that it is important to delete the entire contents of this folder. Although this folder may initially contain
the "missing" android_m2repository_r16.zip file, this file may have been partially downloaded or
corrupted.
4. Rebuild the project – doing so will cause the build process to re-download the missing library.
In most cases, these steps will resolve the build error and allow you to continue. If deleting this library does not
resolve the build error, you must manually download and install the android_m2repository_r_nn_.zip file as
described in the next section.
Manually Downloading m2repository
If you have tried using the automatic recovery steps above and still have build errors, you can manually download
the android_m2repository_r_nn_.zip file (using a web browser) and install it according to the following steps.
This procedure is also useful if you do not have internet access on your development computer but you are able to
download the archive using a different computer.
1. Download the android_m2repository_r_nn_.zip file that corresponds to the error message – links are
provided in the following list (along with the corresponding MD5 hash of each link's URL ):
android_m2repository_r33.zip – 5FB756A25962361D17BBE99C3B3FCC44
android_m2repository_r32.zip – F16A3455987DBAE5783F058F19F7FCDF
android_m2repository_r31.zip – 99A8907CE2324316E754A95E4C2D786E
android_m2repository_r30.zip – 05AD180B8BDC7C21D6BCB94DDE7F2C8F
android_m2repository_r29.zip – 2A3A8A6D6826EF6CC653030E7D695C41
android_m2repository_r28.zip – 17BE247580748F1EDB72E9F374AA0223
android_m2repository_r27.zip – C9FD4FCD69D7D12B1D9DF076B7BE4E1C
android_m2repository_r26.zip – 8157FC1C311BB36420C1D8992AF54A4D
android_m2repository_r25.zip – 0B3F1796C97C707339FB13AE8507AF50
android_m2repository_r24.zip – 8E3C9EC713781EDFE1EFBC5974136BEA
android_m2repository_r23.zip – D5BB66B3640FD9B9C6362C9DB5AB0FE7
android_m2repository_r22.zip – 96659D653BDE0FAEDB818170891F2BB0
android_m2repository_r21.zip – CD3223F2EFE068A26682B9E9C4B6FBB5
android_m2repository_r20.zip – 650E58DF02DB1A832386FA4A2DE46B1A
android_m2repository_r19.zip – 263B062D6EFAA8AEE39E9460B8A5851A
android_m2repository_r18.zip – 25947AD38DCB4865ABEB61522FAFDA0E
android_m2repository_r17.zip – 49054774F44AE5F35A6BA9D3C117EFD8
android_m2repository_r16.zip – 0595E577D19D31708195A83087881EE6
If the m2repository archive is not shown in this table, you can create the download URL by prepending
https://dl-ssl.google.com/android/repository/ to the name of the m2repository to download. For
example, use https://dl-ssl.google.com/android/repository/android\_m2repository\_r10.z to
download android_m2repository_r10.zip.
2. Rename the file to the corresponding MD5 hash of the download URL as shown in the above table. For
example, if you downloaded android_m2repository_r25.zip, rename it to
0B3F1796C97C707339FB13AE8507AF50.zip. If the MD5 hash for the download URL of the downloaded
file is not shown in the table, you can use an online MD5 generator to convert the URL to an MD5 hash
string.
3. Copy the file to the Xamarin zips folder:
On Windows, this folder is located at C:\Users\username\AppData\Local\Xamarin\zips.
On Mac OS X, this folder is located at /Users/username/.local/share/Xamarin/zips.
For example, the following screenshot illustrates the result when android_m2repository_r16.zip is
downloaded and renamed to the MD5 hash of its download URL on Windows:
If this procedure does not resolve the build error, you must manually download the
android_m2repository_r_nn_.zip file, unzip it, and install its contents as described in the next section.
Manually Downloading and Installing m2repository Files
The fully manual process for recovering from m2repository errors entails downloading the
android_m2repository_r_nn_.zip file (using a web browser), unzipping it, and copying its contents to the support
library directory on your computer. In the following example, we'll recover from this error message:
Use the following steps to download m2repository and install its contents:
1. Delete the contents of the library folder corresponding to the error message. For example, in the above
error message you would delete the contents of
C:\Users\username\AppData\Local\Xamarin\Android.Support.v4\23.1.1.0. As described earlier, you
must delete the entire contents of this directory:
2. Download the android_m2repository_r_nn_.zip file from Google that corresponds to the error message
(see the table in the previous section for links).
3. Extract this .zip archive to any location (such as the Desktop). This should create a directory that
corresponds to the name of the .zip archive. Within this directory, you should find a subdirectory called
m2repository:
4. In the versioned library directory that you purged in step 1, re-create the content and embedded
subdirectories. For example, the following screenshot illustrates content and embedded subdirectories
being created in the 23.1.1.0 folder for android_m2repository_r25.zip:
5. Copy m2repository from the extracted .zip into the content directory that you created in the previous
step:
8. Verify that all files are copied over. The embedded directory should now contain files such as .jar, .aar, and
.pom.
9. Unzip the contents of any extracted .aar files to the embedded directory. On Windows, append a .zip
extension to the .aar file, open it, and copy the contents to the embedded directory. On macOS, unzip the
.aar file by using the unzip command in the Terminal (for example, unzip file.aar).
At this point, you have manually installed the missing components and your project should build without errors. If
not, verify that you have downloaded the m2repository .zip archive version that corresponds exactly to the
version in the error message, and verify that you have installed its contents in the correct locations as described in
the above steps.
Summary
This article explained how to recover from common errors that can take place during the automatic download and
installation of dependency libraries. It described how to delete the problematic library and rebuild the project as a
way to re-download and re-install the library. It described how to download the library and install it in the zips
folder. It also described a more involved procedure for manually downloading and installing the necessary files as
a way to work around issues that cannot be resolved via automatic means.
Changes to the Android SDK Tooling
6/25/2018 • 2 minutes to read • Edit Online
Changes to how the Android SDK manages the installed API levels and AVDs.
The following sections explain how to manage the Android SDK and Android Virtual Devices using Android SDK
25.3.0 and later.
UI Tools
Visual Studio and Visual Studio for Mac now provide Xamarin replacements for the discontinued Google GUI-
based managers:
To download Android SDK tools, platforms, and other components that you need for developing
Xamarin.Android apps, use the Xamarin Android SDK Manager instead of the legacy Google SDK
Manager.
To create and configure Android Virtual Devices, use the Android Device Manager instead of the legacy
Google Emulator Manager.
These tools are functionally equivalent to the Google GUI-based managers they replace.
CLI Tools
Alternately, you can use CLI tools to manage and update your emulators and Android SDK. The following
programs now make up the command line interface for the Android SDK tools:
sdkmanager
Added In: Android SDK Tools 25.2.3 (November, 2016) and higher.
There is a new program called sdkmanager in the tools/bin folder of your Android SDK. This tool is used to
maintain the Android SDK at the command line. For more information about using this tool, see sdkmanager.
avdmanager
Added In: Android SDK Tools 25.3.0 (March, 2017) and higher.
There is a new program called avdmanager in the tools/bin folder of your Android SDK. This tool is used to
maintain the AVDs for the Android Emulator. For more information about using this tool, see avdmanager.
Downgrading
You can downgrade your Android SDK Tools version by installing a previous version of the Android SDK from
the Android Developer website.
Using the old GUI
You can still use the original GUI by running the android program inside your tools folder as long as you are on
Android SDK Tools version 25.2.5 or lower.
Related Links
Android SDK Setup
Android Device Manager
Understanding Android API levels
SDK Tools Release Notes (Google)
sdkmanager
avdmanager
Xamarin.Android Errors Matrix
4/12/2018 • 7 minutes to read • Edit Online
Errors Reference
This document provides some information on the various error codes from Xamarin.
CATEGORY DESCRIPTION
XA7xxx Reserved
XA8xxx Reserved
Error Codes
XA0xxx Errors
ERROR CODE DESCRIPTION
XA0011 {0} was built against a more recent runtime ({1}) than
MonoTouch supports.
XA1xxx Errors
ERROR CODE DESCRIPTION
XA1003 Could not kill the application '{0}'. You may have to kill the
application manually.
XA1005 Could not kill the application '{0}' on the device '{1}': {2}. You
may have to kill the application manually.
XA1006 Could not install the application '{0}' on the device '{1}': {2}.
XA1007 Failed to launch the application '{0}' on the device '{1}': {2}. You
can still launch the application manually by tapping on it.
XA1102 Could not attach to the app (to kill it): {0}.
XA1106 Could not get list of applications on the device: Request timed
out.
XA1301 Native library '{0}' ({1}) was ignored since it does not match
the current build architecture(s) ({2}).
XA2xxx Errors
ERROR CODE DESCRIPTION
XA3xxx Errors
These are AOT errors.
XA4104 The registrar cannot marshal the return value for type '{0}' in
signature for method '{1}'.
XA4106 The registrar cannot marshal the return value for structure
'{0}' in signature for method '{1}'.
XA4108 The registrar cannot get the ObjectiveC type for managed
type '{0}'.
XA4110 The registrar cannot marshal the out parameter of type '{0}' in
signature for method '{1}'.
XA4111 The registrar cannot build a signature for type '{0}' in method
'{1}'.
XA5xxx Errors
ERROR CODE DESCRIPTION
XA5103 Failed to compile the file '{0}'. Please file a bug report.
XA5201 Native linking failed. Please review user flags provided to gcc:
{0}
XA5204 Failed to strip the final binary. Please review the build log.
XA5205 Missing 'aapt' tool. Please install the Android SDK Build-tools
package.
XA5208 Download failed. Please download {0} and put it to the {1}
directory.
ERROR CODE DESCRIPTION
XA5209 Unzipping failed. Please download {0} and extract it to the {1}
directory.
XA6xxx Errors
ERROR CODE DESCRIPTION
XA9xxx Errors
These error codes are licensing and activation errors.
XA9000
Cause: License expired
Checked During: Build
XA9001
Cause: Trial Expired
Checked During: Build
XA9002
Cause: AndroidJavaSource
Checked During: Build
ERROR OK OK OK OK
Cause: AndroidJavaLibrary
Checked During: Build
ERROR OK OK OK OK
If a Binding assembly has the .jar embedded, then this is caught at Package time, not Build time.
Cause: AndroidNativeLibrary
Checked During: Build
ERROR OK OK OK OK
XA9003
Cause: System.Runtime.Serialization
Checked During: Package
ERROR ERROR OK OK OK
Cause: System.ServiceModel.Web
Checked During: Package
ERROR ERROR OK OK OK
Cause: Mono.Data.Tds
Checked During: Build
ERROR ERROR OK OK OK
ERROR OK OK OK OK
XA9004
Cause: --profiling
Checked During: Package
ERROR ERROR OK OK OK
XA9005
Cause: Size limit (32kb).
Checked During: Package
STARTER INDIE BUSINESS(TRIAL) BUSINESS ENTERPRISE
ERROR OK - - -
XA9006
Cause: System.Data.SqlClient namespace.
Checked During: Package
ERROR ERROR OK OK OK
XA9008
Cause: Building from command-line.
Checked During: Build
ERROR ERROR OK OK OK
XA9009
Cause: Missing serial number.
Checked During: Untestable
XA9010
Cause: Invalid ProductId.
Checked During: Build
Equivalent to XA9018.
XA9011
Cause: Failed to update license file (to new file format).
Checked During: Activation
XA9012
Cause: No internet
Checked During: Activation
STARTER INDIE BUSINESS(TRIAL) BUSINESS ENTERPRISE
XA9013
Cause: Unknown Error
Checked During: Activation
XA9014
Cause: Invalid Activation Code
Checked During: Activation
XA9017
Cause: Activation server doesn't return a valid license.
Checked During: Activation
XA9018
Cause: Invalid License
Checked During: Build
- - ERROR - -
Android Wear
4/12/2018 • 2 minutes to read • Edit Online
Android Wear is a version of Android that is designed for wearable devices such as smart watches. This section
includes instructions on how to install and configure tools required for Wear development, a step-by-step
walkthrough for creating your first Wear device, and a list of samples that you can refer to for creating your own
Wear apps.
Getting Started
Introduces Android Wear, describes how to install and configure your computer for Wear development, and
provides steps to help you create and run your first Android Wear app on an emulator or Wear device.
User Interface
Explains Android Wear-specific controls and provides links to samples that demonstrate how to use these controls.
Platform Features
Documents in this section cover features specific to Android Wear. Here you'll find a topic that describes how to
create a WatchFace.
Screen Sizes
Preview and optimize your user interface for the available screen sizes.
Wear APIs
The Android Developer site provides detailed information about key Wear APIs such as Wearable Activity, Intents,
Authentication, Complications, Complications Rendering, Notifications, Views, and WatchFace.
Samples
You can find a number of samples using Android Wear (or go directly to github).
Videos
Check out these video links that discuss Xamarin.Android with Wear support:
DESCRIPTION SCREENSHOT
DESCRIPTION SCREENSHOT
The guides in this section introduce Android Wear, describe how to install and configure your computer for Wear
development, and provide steps to help you create and run your first Android Wear app.
Introduction to Wear
Provides a basic overview of Android Wear, describes its key features, lists some of the more popular Android
Wear devices, and provides links to essential Google Android Wear documentation for further reading.
Hello, Wear
This walkthrough provides step-by-step instructions for creating a small Android Wear project that handles button
clicks and displays a click counter on the Wear device.
Introduction to Android Wear
4/12/2018 • 8 minutes to read • Edit Online
With the introduction of Google's Android Wear, you are no longer restricted to just phones and tablets when it
comes to developing great Android apps. Xamarin.Android's support for Android Wear makes it possible for you
to run C# code on your wrist! This introduction provides a basic overview of Android Wear, describes its key
features, and offers an overview of the features available in Android Wear 2.0. It lists some of the more popular
Android Wear devices, and it provides links to essential Google Android Wear documentation for further reading.
Overview
Android Wear runs on a variety of devices, including the first-generation Motorola 360, LG's G watch, and the
Samsung Gear Live. A second generation, including Sony's SmartWatch 3, has also been released with additional
capabilities including built-in GPS and offline music playback. For Android Wear 2.0, Google has teamed up with
LG for two new watches: the LG Watch Sport and the LG Watch Style.
Xamarin.Android 5.0 and later supports Android Wear through our Android 4.4W (API 20) support and a NuGet
package that adds additional Wear-specific UI controls. Xamarin.Android 5.0 and later also includes functionality
for packaging your Wear apps. NuGet packages are also available for Android Wear 2.0 as described later in this
guide.
Wear also makes use of action buttons that consist of a big colored circle with small description text underneath it
(as illustrated above). The GridViewPager sample demonstrates how to use GridViewPager and GridPagerAdapter
in a Wear app.
Android Wear 2.0 adds a navigation drawer, an action drawer, and inline action buttons to the Wear user interface.
For more about Android Wear 2.0 user interface elements, see the Android Anatomy topic.
Communications
Android Wear provides two different communication APIs to facilitate communications between wearable apps
and companion handheld apps:
Data API – This API is similar to a synchronized data store between the wearable device and the handheld device.
Android takes care of propagating changes between wearable and handheld when it is optimal to do so. When the
wearable is out of range, it queues synchronization for a later time. The main entry point for this API is
WearableClass.DataApi . For more information about this API, see the Android Syncing Data Items topic.
Message API – This API makes it possible for you to use a lower level communications path: a small payload is
sent one-way without synchronization between the handheld and wearable apps. The main entry point for this API
is WearableClass.MessageApi . For more information about this API, see the Android Sending and Receiving
Messages topic.
You can choose to register callbacks for receiving those messages via each of the API listener interfaces or,
alternatively, implement a service in your app that derives from WearableListenerService . This service will be
automatically instantiated by Android Wear. The FindMyPhone sample illustrates how to implement a
WearableListenerService .
Deployment
Each wearable app is deployed with its own APK file embedded inside the main application APK. This packaging is
handled automatically in Xamarin.Android 5.0 and later, but must be performed manually for versions of
Xamarin.Android earlier than version 5.0. Working with Packaging explains deployment in more detail.
Going Further
The best way to become familiar with Android Wear is to build and test your first app. The following list provides a
recommended reading order to help you get up to speed quickly:
1. Setup & Installation provides detailed instructions for installing and configuring your development
environment for building Xamarin.Android Wear apps.
2. After you have installed the required packages and configured an emulator or device, see Hello, Wear for
step-by-step instructions that explain how to create a small Android Wear project that handles button clicks
and displays a click counter on the Wear device.
3. Deployment & Testing provides more detailed information about configuring and deploying to emulators
and devices, including instructions on how to deploy your app to a Wear device via Bluetooth.
4. Working with Screen Sizes explains how to preview and optimize your user interface for the various
available screen sizes on Wear devices.
5. Working with Packaging describes the steps for manually packaging Wear apps for distribution on Google
Play.
After you have created your first Wear app, you may want to try building a custom watch face for Android Wear.
Creating a Watch Face provides step-by-step instructions and example code for developing a stripped down digital
watch face service, followed by more code that enhances it to an analog-style watch face with extra features.
For more about complications, see the Android Watch Face Complications topic.
Navigation and Action Drawers
Two new drawers are included in Wear 2.0. The navigation drawer, which appears at the top of the screen, allows
users to navigate between app views (as shown on the left below ). The action drawer, which appears at the bottom
of the screen (as shown on the right), allows users to choose from a list of actions.
For more information about these two new interactive drawers, see the Android Wear Navigation and Actions
topic.
Curved Layouts
Wear 2.0 introduces new features for displaying curved layouts on round Wear devices. Specifically, the new
WearableRecyclerView class is optimized for displaying a list of vertical items on round displays:
WearableRecyclerView extends the RecyclerView class to support curved layouts and circular scrolling gestures.
For more information, see the Android WearableRecyclerView API documentation.
Standalone Apps
Android Wear 2.0 apps can work independently of handheld apps. This means that, for example, a smart watch can
continue to offer full functionality even if the companion handheld device is turned off or far away from the
wearable device. For more information about this feature, see the Android Standalone Apps topic.
Wrist Gestures
Wrist gestures make it possible for users to interact with your app without using the touch screen – users can
respond to the app with a single hand. Two wrist gestures are supported:
Flick wrist out
Flick wrist in
For more information, see the Android Wrist Gestures topic.
There are many more Wear 2.0 features such as inline actions, smart reply, remote input, expanded notifications,
and a new bridging mode for notifications. For more information about the new Wear 2.0 features, see the
Android API Overview.
Devices
Here are some examples of the devices that can run Android Wear:
Motorola 360
LG G Watch
LG G Watch R
Samsung Gear Live
Sony SmartWatch 3
ASUS ZenWatch
Further Reading
Check out Google's Android Wear documentation:
About Android Wear
Android Wear App Design
android.support.wearable library
Android Wear 2.0
Summary
This introduction provided an overview of Android Wear. It outlined the basic features of Android Wear and
included a overview of the features introduced in Android Wear 2.0. It provided links to essential reading to help
developers get started with Xamarin.Android Wear development, and it listed examples of some of the Android
Wear devices currently on the market.
Related Links
Installation and Setup
Getting Started
Setup and Installation
5/2/2018 • 2 minutes to read • Edit Online
This article walks through the installation steps and configuration details required to prepare your computer and
devices for Android Wear development. By the end of this article, you'll have a working Xamarin.Android Wear
installation integrated into Visual Studio for Mac and/or Microsoft Visual Studio, and you'll be ready to start
building your first Xamarin.Android Wear application.
Requirements
The following is required to create Xamarin-based Android Wear apps:
Visual Studio or Visual Studio for Mac – You If you are using Visual Studio, Visual Studio 2015
Professional or later is required.
Xamarin.Android – Xamarin.Android 4.17 or later must be installed and configured with either Visual
Studio or Visual Studio for Mac.
Android SDK - Android SDK 5.0.1 (API 21) or later must be installed via the Android SDK Manager.
Java Developer Kit – Xamarin Android development requires JDK 1.8 if you are developing for API level
24 or greater (JDK 1.8 also supports API levels earlier than 24).
You can continue to use JDK 1.7 if you are developing specifically for API level 23 or earlier.
IMPORTANT
Xamarin.Android does not support JDK 9.
Installation
After you have installed Xamarin.Android, perform the following steps so that you're ready to build and test
Android Wear apps:
1. Install the required Android SDK and tools.
2. Configure a test device.
3. Create your first Android Wear app.
These steps are described in the following sections.
Install Android SDK and tools
Launch the Android SDK Manager:
Visual Studio
Visual Studio for Mac
Ensure that you have the following Android SDK and tools installed:
Android SDK Tools v 24.0.0 or higher, and
Android 4.4W (API20), or
Android 5.0.1 (API21) or higher.
If you do not have the latest SDK and tools installed, download the required SDK tools and the API bits (you may
need to scroll a bit to find them – the API selection is shown below ):
Visual Studio
Visual Studio for Mac
Configuration
Before you can use test your app, you must configure an Android Wear emulator or an actual Android Wear
device.
Android Wear Emulator
Before you can use an Android Wear emulator, you must configure an Android Wear Android Virtual Device
(AVD ) using the Google Emulator Manager:
Visual Studio
Visual Studio for Mac
For more information about setting up an Android Wear emulator, see Debug Android Wear on an Emulator.
Android Wear Device
If you have an Android Wear device such as an Android Wear Smartwatch, You can debug the app on this device
instead of using an emulator. For information about developing with a Wear device, see Debug on a Wear Device.
Create Your First Android Wear App
Follow the Hello, Wear instructions to build your first watch app.
Related Links
SkeletonWear (sample)
Hello, Wear
5/7/2018 • 3 minutes to read • Edit Online
Create your first Android Wear app and run it on a Wear emulator or device. This walkthrough provides step -by-
step instructions for creating a small Android Wear project that handles button clicks and displays a click counter
on the Wear device. It explains how to debug the app using a Wear emulator or a Wear device that is connected
via Bluetooth to an Android phone. It also provides a set of debugging tips for Android Wear.
For more information on setting the target framework, see Understanding Android API Levels.
3. Edit the Main.axml layout
Configure the layout to contain a TextView and a Button for the sample:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:id="@+id/scroll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#000000"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="2dp"
android:text="Main Activity"
android:textSize="36sp"
android:textColor="#006600" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="2dp"
android:textColor="#cccccc"
android:id="@+id/result" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="showNotification"
android:text="Click Me!"
android:id="@+id/click_button" />
</LinearLayout>
</ScrollView>
</FrameLayout>
SetContentView (Resource.Layout.Main);
button.Click += delegate {
text.Text = string.Format ("{0} clicks!", count++);
};
}
}
You may see a Just a minute... message (or some other interstitial screen) at first:
If you are using a watch emulator, it can take a while to start up the app. When you are using Bluetooth, it takes
more time to deploy the app than it would over USB. (For example, it takes about 5 minutes to deploy this app to
an LG G Watch that is Bluetooth-connected to a Nexus 5 phone.)
After the app successfully deploys, the screen of the Wear device should display a screen like the following:
Tap the CLICK ME! button on the face of the Wear device and see the count increment with each tap:
Next Steps
Check out the Wear samples including Android Wear apps with companion Phone apps.
When you are ready to distribute your app, see Working with Packaging.
Related Links
Click Me App (sample)
User Interface
5/2/2018 • 2 minutes to read • Edit Online
The following sections explain the various tools and building blocks that are used to compose user interfaces in
Android Wear apps.
Controls
Explains Android Wear-specific controls and provides links to samples that demonstrate how to use these controls.
Android Wear Controls
4/12/2018 • 2 minutes to read • Edit Online
Android Wear apps can use many of the same controls already in use for regular Android apps, including Button ,
TextView , and image drawables. Layout controls including ScrollView , LinearLayout , and RelativateLayout can
also be used.
This page links to the Android-Wear-specific controls from the wearable UI library available in Xamarin projects
via the Wearable Support NuGet package. These controls include the following:
GridViewPager – Create a two-dimensional navigation interface where the user scrolls down then across
to make a selection (for more information, see GridViewPager):
Related Links
Android.Support.Wearable docs
GridViewPager
4/12/2018 • 2 minutes to read • Edit Online
The GridViewPager sample demonstrates how to implement the 2D picker navigation pattern for Android Wear.
First add the Xamarin Android Wear Support NuGet package to your project.
The layout XML looks like this:
<android.support.wearable.view.GridViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true" />
Create a GridPagerAdapter (or subclass such as FragmentGridPagerAdapter to supply views to display as the user
navigates.
The sample adapter shows how to implement the required methods, including overrides for RowCount ,
GetColumnCount , GetBackground , and GetFragment
Related Links
Google's 2D Picker doc
android.support.wearable docs
GridViewPager (sample)
Platform Features
5/2/2018 • 2 minutes to read • Edit Online
Documents in this section cover features specific to Android Wear. Here you'll find a topic that describes how to
create a WatchFace.
This guide explains how to implement a custom watch face service for Android Wear. Step -by-step instructions are
provided for building a stripped down digital watch face service, followed by more code to create an analog -style
watch face.
Overview
In this walkthrough, a basic watch face service is created to illustrate the essentials of creating a custom Android
Wear watch face. The initial watch face service displays a simple digital watch that displays the current time in
hours and minutes:
After this digital watch face is developed and tested, more code is added to upgrade it to a more sophisticated
analog watch face with three hands:
Watch face services are bundled and installed as part of a Wear app. In the following examples, MainActivity
contains nothing more than the code from the Wear app template so that the watch face service can be packaged
and deployed to the smart watch as part of the app. In effect, this app will serve purely as a vehicle for getting the
watch face service loaded into the Wear device (or emulator) for debugging and testing.
Requirements
To implement a watch face service, the following is required:
Android 5.0 (API level 21) or higher on the Wear device or emulator.
The Xamarin Android Wear Support Libraries must be added to the Xamarin.Android project.
Although Android 5.0 is the minimum API level for implementing a watch face service, Android 5.1 or later is
recommended. Android Wear devices running Android 5.1 (API 22) or higher allow Wear apps to control what's
displayed on the screen while the device is in low -power ambient mode. When the device leaves low -power
ambient mode, it is in interactive mode. For more about these modes, see Keeping Your App Visible.
Visual Studio
Visual Studio for Mac
In addition, scroll down and enable the INTERNET and WAKE_LOCK permissions:
Next, download preview.png – this will be added to the drawables folder later in this walkthrough.
Build and run the app on a Wear device or emulator (for more information about how to do this, see the Getting
Started guide). You should see the following app screen on the Wear device:
At this point, the basic Wear app does not have watch face functionality because it does not yet provide a watch
face service implementation. This service will be added next.
CanvasWatchFaceService
Android Wear implements watch faces via the CanvasWatchFaceService class. CanvasWatchFaceService is derived
from WatchFaceService , which itself is derived from WallpaperService as shown in the following diagram:
Not shown in this diagram is a Canvas that CanvasWatchFaceService uses for drawing the watch face – this Canvas
is passed in via the OnDraw method as described below.
In the following sections, a custom watch face service will be created by following these steps:
1. Define a class called MyWatchFaceService that is derived from CanvasWatchFaceService .
2. Within MyWatchFaceService, create a nested class called MyWatchFaceEngine that is derived from
CanvasWatchFaceService.Engine .
3. In MyWatchFaceService , implement a CreateEngine method that instantiates MyWatchFaceEngine and returns
it.
4. In MyWatchFaceEngine , implement the OnCreate method to create the watch face style and perform any
other initialization tasks.
5. Implement the OnDraw method of MyWatchFaceEngine . This method is called whenever the watch face needs
to be redrawn (i.e. invalidated). OnDraw is the method that draws (and redraws) watch face elements such
as hour, minute, and second hands.
6. Implement the OnTimeTick method of MyWatchFaceEngine . OnTimeTick is called at least once per minute (in
both ambient and interactive modes) or when the date/time has changed.
For more information about CanvasWatchFaceService , see the Android CanvasWatchFaceService API
documentation. Similarly, CanvasWatchFaceService.Engine explains the actual implementation of the watch face.
Add the CanvasWatchFaceService
Visual Studio
Visual Studio for Mac
Add a new file called MyWatchFaceService.cs (in Visual Studio, right-click WatchFace in the Solution
Explorer, click Add > New Item..., and select Class).
Replace the contents of this file with the following code:
using System;
using Android.Views;
using Android.Support.Wearable.Watchface;
using Android.Service.Wallpaper;
using Android.Graphics;
namespace WatchFace
{
class MyWatchFaceService : CanvasWatchFaceService
{
public override WallpaperService.Engine OnCreateEngine()
{
return new MyWatchFaceEngine(this);
}
MyWatchFaceService (derived from CanvasWatchFaceService ) is the "main program" of the watch face.
MyWatchFaceService implements only one method, OnCreateEngine , which instantiates and returns a
MyWatchFaceEngine object ( MyWatchFaceEngine is derived from CanvasWatchFaceService.Engine ). The instantiated
MyWatchFaceEngine object must be returned as a WallpaperService.Engine . The encapsulating MyWatchFaceService
object is passed into the constructor.
MyWatchFaceEngine is the actual watch face implementation – it contains the code that draws the watch face. It also
handles system events such as screen changes (ambient/interactive modes, screen turning off, etc.).
Implement the Engine OnCreate Method
The OnCreate method initializes the watch face. Add the following field to MyWatchFaceEngine :
Paint hoursPaint;
This object will be used to draw the current time on the watch face. Next, add the following method to
Paint
MyWatchFaceEngine :
OnCreate is called shortly after MyWatchFaceEngine is started. It sets up the WatchFaceStyle (which controls how
the Wear device interacts with the user) and instantiates the Paint object that will be used to display the time.
The call to SetWatchFaceStyle does the following:
1. Sets peek mode to PeekModeShort , which causes notifications to appear as small "peek" cards on the display.
2. Sets the background visibility to Interruptive , which causes the background of a peek card to be shown
only briefly if it represents an interruptive notification.
3. Disables the default system UI time from being drawn on the watch face so that the custom watch face can
display the time instead.
For more information about these and other watch face style options, see the Android WatchFaceStyle.Builder API
documentation.
After SetWatchFaceStyle completes, OnCreate instantiates the Paint object ( hoursPaint ) and sets its color to
white and its text size to 48 pixels (TextSize must be specified in pixels).
Implement the Engine OnDraw Method
The OnDraw method is perhaps the most important CanvasWatchFaceService.Engine method – it is the method that
actually draws watch face elements such as digits and clock face hands. In the following example, it draws a time
string on the watch face. Add the following method to MyWatchFaceEngine :
When Android calls OnDraw , it passes in a Canvas instance and the bounds in which the face can be drawn. In the
above code example, DateTime is used to calculate the current time in hours and minutes (in 12-hour format). The
resulting time string is drawn on the canvas by using the Canvas.DrawText method. The string will appear 70 pixels
over from the left edge and 80 pixels down from the top edge.
For more information about the OnDraw method, see the Android [onDraw ]
(https://developer.android.com/reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.
html#onDraw (android.graphics.Canvas, android.graphics.Rect)) API documentation.
Implement the Engine OnTimeTick Method
Android periodically calls the OnTimeTick method to update the time shown by the watch face. It is called at least
once per minute (in both ambient and interactive modes), or when the date/time or timezone have changed. Add
the following method to MyWatchFaceEngine :
This implementation of OnTimeTick simply calls Invalidate . The Invalidate method schedules OnDraw to
redraw the watch face.
For more information about the OnTimeTick method, see the Android onTimeTick API documentation.
<service
android:name="watchface.MyWatchFaceService"
android:label="Xamarin Sample"
android:allowEmbedded="true"
android:taskAffinity=""
android:permission="android.permission.BIND_WALLPAPER">
<meta-data
android:name="android.service.wallpaper"
android:resource="@xml/watch_face" />
<meta-data
android:name="com.google.android.wearable.watchface.preview"
android:resource="@drawable/preview" />
<intent-filter>
<action android:name="android.service.wallpaper.WallpaperService" />
<category android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
</intent-filter>
</service>
2. Defines a watch_face resource. This resource is a short XML file that declares a wallpaper resource (this
file will be created in the next section).
3. Declares a drawable image called preview that will be displayed by the watch picker selection screen.
4. Includes an intent-filter to let Android know that MyWatchFaceSevice will be displaying a watch face.
That completes the code for the basic WatchFace example. The next step is to add the necessary resources.
Add Resource Files
Before you can run the watch service, you must add the watch_face resource and the preview image. First, create
a new XML file at Resources/xml/watch_face.xml and replace its contents with the following XML:
This resource file defines a simple wallpaper element that will be used for the watch face.
If you have not yet done so, download preview.png. Install it at Resources/drawable/preview.png. Be sure to
add this file to the WatchFace project. This preview image is displayed to the user in the watch face picker on the
Wear device. To create a preview image for your own watch face, you can take a screenshot of the watch face while
it is running. (For more about getting screenshots from Wear devices, see Taking screenshots).
Try It!
Build and deploy the app to the Wear device. You should see the Wear app screen appear as before. Do the
following to enable the new watch face:
1. Swipe to the right until you see the background of the watch screen.
2. Touch and hold anywhere on the background of the screen for two seconds.
3. Swipe from left to right to browse through the various watch faces.
4. Select the Xamarin Sample watch face (shown on the right):
5. Tap the Xamarin Sample watch face to select it.
This changes the watch face of the Wear device to use the custom watch face service implemented so far:
This is a relatively crude watch face because the app implementation is so minimal (for example, it doesn't include
a watch face background and it doesn't call Paint anti-alias methods to improve the appearance). However, it
does implement the bare-bones functionality that is required to create a custom watch face.
In the next section, this watch face will be upgraded to a more sophisticated implementation.
This example includes only one xamarin_background.png image; however, you may want to create a different
background image for each screen density that your custom watch face will support.
OnDraw
The updated OnDraw method draws an analog-style watch face using the following steps:
1. Gets the current time, which is now maintained in a time object.
2. Determines the bounds of the drawing surface and its center.
3. Draws the background, scaled to fit the device when the background is drawn.
4. Draws twelve ticks around the face of the clock (corresponding to the hours on the clock face).
5. Calculates the angle, rotation, and length for each watch hand.
6. Draws each hand on the watch surface. Note that the second hand is not drawn if the watch is in ambient
mode.
OnPropertiesChanged
This method is called to inform MyWatchFaceEngine about the properties of the Wear device (such as low -bit
ambient mode and burn-in protection). In MyWatchFaceEngine , this method only checks for low bit ambient mode
(in low bit ambient mode, the screen supports fewer bits for each color).
For more information about this method, see the Android onPropertiesChanged API documentation.
OnAmbientModeChanged
This method is called when the Wear device enters or exits ambient mode. In the MyWatchFaceEngine
implementation, the watch face disables anti-aliasing when it is in ambient mode.
For more information about this method, see the Android onAmbientModeChanged API documentation.
OnVisibilityChanged
This method is called whenever the watch becomes visible or hidden. In MyWatchFaceEngine , this method
registers/unregisters the time zone receiver (described below ) according to the visibility state.
For more information about this method, see the Android onVisibilityChanged API documentation.
Time Zone Feature
The new MyWatchFaceService.cs also includes functionality to update the current time whenever the time zone
changes (such as while traveling across time zones). Near the end of MyWatchFaceService.cs, a time zone
change BroadcastReceiver is defined that handles timezone-changed Intent objects:
public class TimeZoneReceiver: BroadcastReceiver
{
public Action<Intent> Receive { get; set; }
public override void OnReceive (Context context, Intent intent)
{
if (Receive != null)
Receive (intent);
}
}
An intent filter is created and registered for the time zone receiver:
Application.Context.UnregisterReceiver (timeZoneReceiver);
In this screenshot, the second hand is moving once per second. When you run this code on a Wear device, the
second hand disappears when the watch enters ambient mode.
Summary
In this walkthrough, a custom Android Wear watchface was implemented and tested. The CanvasWatchFaceService
and CanvasWatchFaceService.Engine classes were introduced, and the essential methods of the engine class were
implemented to create a simple digital watch face. This implementation was updated with more functionality to
create an analog watch face, and additional methods were implemented to handle changes in visibility, ambient
mode, and differences in device properties. Finally, a time zone broadcast receiver was implemented so that the
watch automatically updates the time when a time zone is crossed.
Related Links
Creating Watch Faces
WatchFace sample
WatchFaceService.Engine
Working with Screen Sizes
5/2/2018 • 2 minutes to read • Edit Online
Android Wear devices can have either a rectangular or a round display, which can also be different sizes.
<android.support.wearable.view.WatchViewStub
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/stub"
app:rectLayout="@layout/rect_layout"
app:roundLayout="@layout/round_layout" />
The solution contains different layouts for each style which will be selected at run-time:
BoxInsetLayout
Rather than build different layouts for each screen type, you can also create a single view that adapts to
rectangular or round screens.
This Google example shows how to use the BoxInsetLayout to use the same layout on both rectangular and round
screens.
Wear UI Designer
The Xamarin Android Designer supports both rectangular and round screens:
Wear Simulator
The Google Emulator Manager contains device definitions for both screen types. You can create rectangular and
round emulators to test your app.
Video
Fullscreen apps for Android Wear from developers.google.com.
Deployment and Testing
5/2/2018 • 2 minutes to read • Edit Online
This section explains how to test your Android Wear app on an Android Wear device (or on an Android emulator
configured for Wear). It also includes debugging tips and information for how to set up a Bluetooth connection
between your development computer and an Android device. When your app is ready, the last topic explains how
to prepare your app for deployment.
The emulator may be left running; it is not necessary to shut it down and restart it each time the app is run.
Summary
This guide explained how to configure the Android Emulator for Wear development and launch a Wear virtual
device for debugging.
Debug on a Wear Device
4/12/2018 • 3 minutes to read • Edit Online
This article explains how to debug a Xamarin.Android Wear application on a Wear device.
Overview
If you have an Android Wear device such as an Android Wear Smartwatch, You can run the app on the device
instead of using an emulator. (If you are not yet familiar with the process of deploying and running Android Wear
apps, see Hello, Wear.)
4. Connect the phone to your computer over USB. On your computer, enter the following commands:
If port 4444 is not available, you can use any other available port to which you have access.
Note: If you restart Visual Studio or Visual Studio for Mac, you must run these commands again to setup a
connection to the Wear device.
5. When the Wear device prompts you, confirm that you are allowing ADB Debugging. In the Android Wear
app, you should see the status change to:
Host: connected
Target: connected
6. After you complete the above steps, running adb devices shows the status of both the phone and the
Android Wear device:
At this point, you can deploy your app to the Wear device.
Taking screenshots
You can take a screenshot of the Wear device by entering the following command:
Uninstalling an app
You can uninstall an app from the wear device by entering the following command:
For example, to remove the app with the package name com.xamarin.weartest , enter the following command:
Summary
This article explained how to configure an Android Wear device for Wear debug from Visual Studio via Bluetooth,
and how to debug a Wear app with a companion phone app. It also provided common debugging tips for
debugging a Wear app via Bluetooth.
Packaging Wear Apps
4/12/2018 • 2 minutes to read • Edit Online
Android Wear apps are packaged with a full Android app for distribution on Google Play.
Automatic Packaging
Starting with Xamarin Android 5.0, your Wear app is automatically packaged as a resource in your Handheld app
when you create a project reference from the Handheld project to the Wear project. You can use the following
steps to create this association:
Visual Studio
Visual Studio for Mac
1. If your Wear app is not already part of your Handheld solution, right-click the solution node and select
Add > Add Existing Project....
2. Navigate to the .csproj file of your Wear app, select it, and click Open. The Wear app project should now
be visible in your Handheld solution.
3. Right-click the References node and select Add Reference.
4. In the Reference Manager dialog, enable your Wear project (click to add a check mark), then click OK.
5. Change the package name for your Wear project so that it matches the package name of the Handheld
project (the package name can be changed under Properties > Android Manifest).
Note that you will get an XA5211 error if the package name of the Wear app does not match the package name
of the Handheld app. For example:
Error XA5211: Embedded wear app package name differs from handheld
app package name (com.companyname.mywearapp != com.companyname.myapp). (XA5211)
To correct this error, change the package name of the Wear app so that it matches the package name of the
Handheld app.
When you click Build > Build All, this association triggers automatic packaging of the Wear project into the
main Handheld (Phone) project. The Wear app is automatically built and included as a resource in the Handheld
app.
The assembly that the Wear app project generates is not used as an assembly reference in the Handheld (Phone)
project. Instead, the build process does the following:
Verifies that the package names match.
Generates XML and adds it to the Handheld project to associate it with the Wear app. For example:
Manual Packaging
You can write Android Wear apps in Xamarin.Android before version 5.0, but you must follow these manual
packaging instructions to distribute the app:
1. Ensure that your Wearable project and Handheld (Phone) projects have the same version number and
package name.
2. Manually build the Wearable project as a Release build.
3. Manually add the release .APK from step (2) into the Resources/raw directory of the Handheld (Phone)
project.
4. Manually add a new XML resource Resources/xml/wearable_app_desc.xml in the Handheld project
which refers to Wearable APK from step (3):
<wearableApp package="wearable.app.package.name">
<versionCode>1</versionCode>
<versionName>1.0</versionName>
<rawPathResId>NAME_OF_APK_FROM_STEP_3</rawPathResId>
</wearableApp>
5. Manually add a <meta-data /> element to the Handheld project's AndroidManifest.xml <application>
element that refers to the new XML resource:
<meta-data android:name="com.google.android.wearable.beta.app"
android:resource="@xml/wearable_app_desc"/>