---
title: Breezing Through Android Boilerplate with Custom Activity Templates
teaser: A guide on how to create activity templates for Android Studio.
tags: kotlin,android,mobile
author: Alex Sullivan
published_on: 2017-11-29
---

If you're an Android developer, chances are you've written a looooot of screens
that show a list of something or another. Chances are you'll also write a lot
more. And my guess is that they all look pretty similar - an activity with a
layout that has a `RecyclerView` in it. Maybe it's wrapped in a `FrameLayout`
or something to house a FAB. Then you have an `Adapter`. And that `Adapter`
has a custom `ViewHolder`.  And that `ViewHolder` references another new layout
file. And you probably have a `List` of something being passed into the
`Adapter`. Oh and you probably have some type of `interface` callback between
the `Activity` and the `Adapter`. It probably has a method that sounds something
like `fun itemClicked(myItem: MyItem)` in it.

That there boilerplate makes me sleepy just typing it out. But good news, boys
and girls, we can avoid all (most...) of that by using a custom activity
template.

## What is an activity template?

The templates that I'm talking about are the same ones you see when you go to
create a new file and choose to go through the IDE's wizard for creating a
new activity or fragment or service or whatever you want.  It provides you
with a little wizard where you fill in a few values and it generates a whole
bunch of code, including multiple source files (which is key for our
`RecyclerView` example). They're even smart enough to do things like add your
new activity into your `AndroidManifest` file. Nifty, right?

## What makes up a custom template?

All of Android Studios built-in wizard-style templates can be found in
`(YOUR_ANDROID_STUDIO_LOCATION)/plugins/android/lib/templates`. They utilize the
[FreeMarker language](https://freemarker.apache.org/), which is a
templating language used to generate HTML/Source files/emails etc. Its syntax
is pretty basic: You use `${blah}` to denote dynamic text that references a
function or a variable. Everything else is normal static text.

Each template lives in its own folder and has 4 core components:

a `template.xml` file:

This is where all of the user facing components are declared - i.e. what the
templates name will be, what category it'll be in, what kind of fields it
expects from the user and so on. It's also the entrance point to the rest of
your template.

a `globals.xml.ftl` file:

This file declares global variables that can be used throughout the template.
For example - your `Activity` layout file name may go here so it can be reused
in other components.

A `root` directory:

The `root` directory is what ultimately contains your template code - so if
you're creating an activity template this is where your 'skeleton' activity
would go. This is where the actual Java or Kotlin code lives.

* Note that the `root` directory (almost) always contains a `src` directory
  which contains an `app_package` directory which then ACTUALLY contains your
  template code. The idea is that the `root` directory is supposed to have a
  list of directories that roughly emulates your output directory, but with all
  that middle nonsense replaced with app_package for convenience.

And finally, the `recipe.xml.ftl` file:

This is the file that actually ties everything together and declares what code
will be generated.  The bulk of the recipe file has code blocks that look
something like this:

```xml
<instantiate from="src/app_package/Adapter.kt.ftl"
to="${escapeXmlAttribute(srcOut)}/${activityName}Adapter.kt" />
```

Which is saying "Create a file based off the skeleton located at
src/app_package/Adapter.kt.ftl (filling in any necessary information provided by
the user) and place it in the users source directory with the name (whatever the
user put in)Adapter.kt"

## Creating a new template

Onto the meat of the subject - writing our own template. Each template lives in
its own folder, so you need to create a new folder and put it in the activities
directory. You can name the folder whatever you want - for the example below
I named mine `RecyclerviewActivity`.

Now we want to create the `template.xml` file:

```xml
<template
    format="4"
    revision="1"
    name="Recyclerview Activity"
    description="Create an activity hooked up to a recyclerview." >

    <category value="Activity" />

    <parameter
        id="activityName"
        name="Activity Name"
        type="string"
        constraints="class|unique|nonempty"
        default="BallerFeature"
        help="Name of your new Activity" />

    <globals file="globals.xml.ftl" />
    <execute file="recipe.xml.ftl" />

</template>
```

Most of this is pretty self explanatory - the name/description params in the
root template tag will be what the user sees when they open the wizard. The
category determines what bucket the wizard is placed in.

![](https://images.thoughtbot.com/blog-vellum-image-uploads/hgX4OFHQR2pxZzyGg6Eg_name_description.png)

![](https://images.thoughtbot.com/blog-vellum-image-uploads/FyndNF4ARXaC2LFCULa4_category_bucket.png)

The interesting piece is the `parameter` value - this is what the user will
actually be asked to fill in. You can provide defaults and help text and all
that jazz. You can even add constraints like "Must be a valid Java class
identifier" or "Must be a unique class name". The `id` value is how you can
refer to the value in the rest of the template.

The last two lines declare where our global variables live, and finally tell the
template wizard to run the recipe file, which we'll create later on.

Next we want to create our `globals.xml.ftl` file (the one we referenced above):

```xml
<?xml version="1.0"?>
<globals>
    <global id="resOut" value="${resDir}" />
    <global id="srcOut" value="${srcDir}/${slashedPackageName(packageName)}" />
    <global id="listItem" value="${classToResource(activityName)}_list_item" />
    <global id="adapter" value="${activityName}Adapter" />
    <global id="viewholder" value="${activityName}ViewHolder" />
    <global id="activityLayout" value="activity_${classToResource(activityName)}" />
     <!-- These values are all necessary to utilize the manifest merging code
      included below -->
    <#include "../common/common_globals.xml.ftl" />
    <global id="parentActivityClass" value=""/>
    <global id="excludeMenu" type="boolean" value="true" />
    <global id="generateActivityTitle" type="boolean" value="false" />
    <global id="hasNoActionBar" type="boolean" value="false" />
    <global id="isLauncher" type="boolean" value="false" />
    <global id="activityClass" value="${activityName}Activity" />
</globals>
 ```

As previously mentioned, these variables can be referenced throughout the
template.  We're declaring several variables that will be used throughout our
skeleton files - the name of our list item layout, the adapter class and so on.
They utilize the `activityName` we got from the user above.

The `<#include />` line is being used to include a bunch of common globals in
the activities folder - we don't actually care about any of those values, but to
get manifest merging to work properly we need to include them. The same goes for
the rest of the variables below that line.

Next up on the chopping block is our actual skeleton files - these go in the new
`root/src/app_package/` directory.

First we create our recyclerview adapter skeleton `Adapter.kt.ftl`:

```kotlin
package ${packageName}

import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup

class ${adapter}: RecyclerView.Adapter<${adapter}.${viewholder}>() {

  override fun onBindViewHolder(holder: ${activityName}ViewHolder?, position: Int) {
    TODO("not implemented")
  }

  override fun getItemCount(): Int {
    TODO("not implemented")
  }

  override fun onCreateViewHolder(parent: ViewGroup,
    viewType: Int): ${viewholder} {
    val view = LayoutInflater.from(parent.context).inflate(R.layout.${listItem}, parent, false)
    return ${viewholder}(view)
  }

  class ${viewholder}(root: View): RecyclerView.ViewHolder(root)

  interface  Callback {
    fun itemClicked()
  }
}
```

It's utilizing the `adapter` variable we declared above in the `globals.xml.ftl`
file as the class name, and the `listItem` value we declared in our
`globals.xml.ftl` file as the name for the layout file used by the `ViewHolder`.
It's also utilizing the `viewholder` variable simlarly declared in our globals
file to name the `ViewHolder` class.

Next we create our list item layout skeleton `List_Item.xml.ftl`:

```xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="horizontal"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello, World!"/>

</LinearLayout>
```

Nothing too crazy going on there.

Next up is our `Activity` layout skeleton, `Activity_Layout.xml.ftl`:

```xml
<?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">

  <android.support.v7.widget.RecyclerView
      android:id="@+id/list"
      android:layout_width="match_parent"
      android:layout_height="match_parent" />

</FrameLayout>
```

Pretty boring.

Last up is our `Activity` skeleton, `Activity.kt.ftl`:

```kotlin
package ${packageName}

import android.os.Bundle
import android.support.v7.app.AppCompatActivity

class ${activityName}Activity: AppCompatActivity(), ${adapter}.Callback {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.${activityLayout})
  }

  override fun itemClicked() {
    TODO("not implemented")
  }
}
```

It also utilizes the `activityName` we got from the user. It implements the
`Callback` we declared in the `Adapter.kt.ftl` skeleton and sets the
`contentView` to the layout file declared in `Activity_Layout.xml.ftl`.

Finally, to tie it all together, we create the `recipe.xml.ftl` file:

```xml
<?xml version="1.0"?>
<recipe>
    <#include "../common/recipe_manifest.xml.ftl" />

    <instantiate from="src/app_package/Activity.kt.ftl"
                 to="${escapeXmlAttribute(srcOut)}/${activityName}Activity.kt" />

    <instantiate from="src/app_package/Activity_Layout.xml.ftl"
                 to="${escapeXmlAttribute(resOut)}/layout/${activityLayout}.xml"/>

    <instantiate from="src/app_package/List_Item.xml.ftl"
                 to="${escapeXmlAttribute(resOut)}/layout/${listItem}.xml" />

    <instantiate from="src/app_package/Adapter.kt.ftl"
                 to="${escapeXmlAttribute(srcOut)}/${adapter}.kt" />

    <open file="${srcOut}/${activityName}Activity.kt"/>
    <open file="${resOut}/layout/${activityLayout}.xml" />
    <open file="${srcOut}/${adapter}.kt" />
    <open file="${resOut}/layout/${listItem}.xml" />
</recipe>
```

It instantiates four files - first it utilizes the `Activity.kt.ftl` skeleton
file to create the actual activity implementation. The newly created file is
placed wherever `srcOut` points to and is named `activityName`Activity - so
whatever the user input as the activity name followed by Activity.

It then does the same instantiation dance for `Activity_layout.xml.ftl`,
`List_Item.xml.ftl`, and `Adapter.kt.ftl`

But before it instantiates any of the above classes, there's an `<#include />`
line. That's how we get our newly created activity to be added to the
`AndroidManifest` file. The included file utilizes the `<merge />` tag under the
hood to create a new `AndroidManifest` file and merge it into the existing one.
Luckily this code is all included in the `common` directory so we don't need to
write any of it ourselves. 👍 to laziness. This merging code is why we needed
all those extra params in the `globals.xml.ftl` file - it expects those
globals to be present and throws a series of (brutally) opaque errors if it
can't find them.

 ![](https://images.thoughtbot.com/blog-vellum-image-uploads/k5woho5KRFaLUWtE9Enz_final_example.gif)

 And that's it! If you navigate to `File -> New -> Activity` you should see
`Recyclerview Activity` as an option. Boilerplate generated!

 You can find some (admittedly old) [documentation here](https://android.googlesource.com/platform/sdk/+/refs/heads/master/templates/docs/index.html).
