Blog Post

Sample code for this post can be found at https://github.com/petermajor/SearchViewLayout

A year ago I wrote a post where I demonstrated embedding Java code in a Xamarin application. While the concept was pretty cool it was a contrived example.

I recently came across a Android Library written in Java that I considered using in my application. So here is an example of using a real-world Java library in a Xamarin Android application.

Background

I wanted to have a search box in a toolbar. When a user taps on the search box it would expand and allow the user to type in the box.

This behavior can be seen in Google Maps and the Android Phone application. Fortunately for me, a very talented developer has already created an Android library to implement this behavior:

https://github.com/sahildave/Search-View-Layout

Search

Android Library Project

So how do we use this Java library in our Xamarin application?

There are two things we need to do:

  • embed the Java library in our application

  • generate bindings that allow our C# code to call Java code

Embed the Library

On the github page, the developer indicates that this component is available at Maven Central:

dependencies { compile 'xyz.sahildave:searchviewlayout:0.4' }

So we can search Maven Central to get the Java binary:

http://search.maven.org/#search%7Cga%7C1%7Cxyz.sahildave

On the search result, there is a link to download an .aar - click on that.

An .aar is a binary distribution of an Android library project. It is a self-contained library that contains java code and resources.

Android Binding Library

We can use this java libary in our app. However, to be able to get and set properties on the component from C# code, we need to generate a binding library first. Let’s do that…

In the application solution, add a new project.

When prompted to choose a template, select Android Binding Libary:

New Android Binding Library

Right-click on the Jars folder and add the .aar file we downloaded previously to that folder.

Right-click on the .aar, select Build Action from the menu and ensure that Library Project Zip is selected.

Library Project Zip

This instructs the compiler that this is a library file. The contents of this file (code, resources, manifest etc) will be merged into the application at compile time.

Build the binding project to make sure it compiles…

References

The project compiles without errors.

Having made binding libraries before, I can assure you that the absence of errors does not mean that the binding generation worked.

It is imperative that we check the build output for skipped classes.

If the binding generator finds things it can’t resolve, it quite often skips it and outputs a warning.

Searching through the build output for warning I eventually come across this:

JARTOXML: warning J2XA006: missing class error was raised while reflecting xyz.sahildave.widget.SearchViewLayout : android/support/v7/widget/Toolbar.

The generator has essentially skipped the main class of the package… that’s not good!

OK, the ‘warning’ states that it couldn’t find Toolbar class.

We must add references to the packages used by the .aar library to our binding library.

Let’s look at sahildave’s code to see what’s he’s referenced.

The important bit is the dependencies at the bottom:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:23.1.1'
    compile 'com.android.support:cardview-v7:23.1.1'
}

So we need to add the AppCompat and CardView packages to our binding library too.

Here’s the package list:

Packages

Compile again… no more warnings!

That’s all done. The compiler has done all the heavy lifting and generated us a binding library.

It’s not quite perfect, but we’ll get to that in a minute…

Let’s try using the SearchViewLayout.

Using the Library

First, we add a reference to binding project in our main application.

Next, we include the component in our toolbar layout file, as per developer’s documentation on github:

<android.support.design.widget.AppBarLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:id="@+id/appbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        local:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        local:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

    <include layout="@layout/widget_search_bar"/>

</android.support.design.widget.AppBarLayout>

Let’s run the app and see how it looks:

Library Project Zip

If you click on the search box it will crash, but that’s just because we haven’t implemented a fragment for the component to show when the edit view is tapped.

More On Bindings

One of the cool things about the binding generator is that it attempts to c sharp-ify some of the java code.

In sahildave’s documentation, it shows adding adding a listener to be notified of when expand / collapse animations start and finish:

searchViewLayout.setOnToggleAnimationListener(new SearchViewLayout.OnToggleAnimationListener() {
    @Override
    public void onStart(boolean expanded) {
        if(expanded) {
            fab.hide();
        } else {
            fab.show();
        }
    }

    @Override
    public void onFinish(boolean expanded) { }
});

It’s still possible to use the listener… but wanna see something cool?

The generator has added events called Start and Finish that represent the onStart and onFinish methods of listener.

So we can write code like this:

var searchViewLayout = FindViewById<Xyz.Sahildave.Widget.SearchViewLayout> ();
searchViewLayout.Start += (sender, e) => { fab.Hide(); };

Customizing Bindings

Before we finish, I wanted to show you another important part of binding libraries… customizing the bindings.

Let’s continue the previous discussion of converting listeners to events.

I could reasonably argue that Start isn’t a great name for the onStart method of the OnToggleAnimationListener.

Don’t worry, we can customize the names of the bindings.

In the binding library we created, there is a file named Metadata.xml.

In that file we can override all kinds of binding settings.

To change the name of our Start event, let’s add a line to this file:

<metadata>
   <attr path="/api/package[@name='xyz.sahildave.widget']/interface[@name='SearchViewLayout.OnToggleAnimationListener']/method[@name='onStart']" name="eventName">ToggleAnimationStarted</attr>
</metadata>

Now the C# code we write looks like this:

var searchViewLayout = FindViewById<Xyz.Sahildave.Widget.SearchViewLayout> (Resource.Id.search_view_container);
searchViewLayout.ToggleAnimationStarted += (sender, e) => { fab.Hide(); };

One more example…

Due to some technical reasons, the generator cannot know the names of parameters in Java methods.

So when it generates the StartEventArgs class from the onStart method of OnToggleAnimationListener it doesn’t know the parameter name is expanded

Therefore, the generator names the variable a very unhelpful P0.

Without customization, our code would look like this:

var searchViewLayout = FindViewById<Xyz.Sahildave.Widget.SearchViewLayout> (Resource.Id.search_view_container);
searchViewLayout.ToggleAnimationStarted += (sender, e) =>
{
    if (e.P0)
        fab.Hide();
    else
        fab.Show();
};

So let’s add another line to our Metadata.xml file:

<metadata>
   <attr path="/api/package[@name='xyz.sahildave.widget']/interface[@name='SearchViewLayout.OnToggleAnimationListener']/method[@name='onStart']" name="eventName">ToggleAnimationStarted</attr>
   <attr path="/api/package[@name='xyz.sahildave.widget']/interface[@name='SearchViewLayout.OnToggleAnimationListener']/method[@name='onStart']/parameter[@name='p0']" name="name">expanding</attr>
</metadata>

And now our code looks like this:

var searchViewLayout = FindViewById<Xyz.Sahildave.Widget.SearchViewLayout> (Resource.Id.search_view_container);
searchViewLayout.ToggleAnimationStarted += (sender, e) =>
{
    if (e.Expanding)
        fab.Hide();
    else
        fab.Show();
};

The Metadata.xml file is a complicated beast with too many examples to go through here.

There is full documentation over at the Xamarin site.

Wrap up

It’s worth noting that most of Xamarin.Android is bindings over Java code.

Ever used the Activity class from C#? Of course you have… That’s all possible because of the magic of bindings.

The Xamarin developer community is a great group of people who have contributed some amazing community content.

However, there are many more Java Android developers than Xamarin developers.

You will eventually find a component you want to use that is in Maven Central and not Nuget.

Well now you know how… go for it!

In my next post, I’ll show you how to something similar for Xamarin.iOS.