Android Studio Live Templates
Code completion can improve your productivity by reducing how much you have to type, but there are situations when a more powerful tool is needed. Thanks to Android Studio and IntelliJ, live templates make it much easier to focus on just the things you care about.
Live Templates
Live Templates are code snippets that I can insert into my code by typing their abbreviation and pressing tab
. They live in the Editor section of the Preferences.
A template contains hard-coded text and placeholder tokens (or variables). The parts that are marked by the $
character on either end are variables and normally would be the things that I’d be expected to type in.
For example, one of the built-in templates looks like this:
for(int $INDEX$ = 0; $INDEX$ < $LIMIT$; $INDEX$++) {
$END$
}
Here, we have three variables $INDEX$
, $LIMIT$
and $END$
.
$END$
is a special predefined variable that controls where your cursor will be placed once you’re done filling out the template. We will have to fill out the values of the other two.- To use this template, I will type
fori
in the Java file and presstab
. Android Studio will expand the template and put the cursor on the first variable that needs to be replaced. In this case, it will put the cursor where the template has the$INDEX$
token. - As I type something, the other two places where
$INDEX$
appears will copy what I’m typing, live! - When I’m done naming the index variable, I will press
tab
orreturn
and the cursor will move to the next variable that needs to be defined, which is$LIMIT$
. - Finally, after I finish typing in the
$LIMIT$
variable, pressingtab
orreturn
will place the cursor where the$END$
variable is and will stop the template fill-out session.
Templates in Action
Let’s look at a more complex example.
In our Android Programming Guide, we use the newIntent
pattern for Activities and the newInstance
pattern for Fragments. Typically, creating a new Activity/Fragment pair involves the following steps:
- Create the
newIntent
method in the activity. - Create the constant(s) for the names of extras to be passed with the
Intent
. - Create the
getFragment
method that reads theIntent
extras and passes them on to the fragment’snewInstance
method. - Create the
newInstance
method in the fragment. - Create the constant(s) for the names of the arguments to be set on the fragment.
- Create the instance variable(s) to store the values of the arguments.
- Read the arguments in the
onCreate
method.
In this video, I demonstrate how live templates make it much easier to focus on just the things I care about, rather than the boilerplate.
In the first part of the video, I’m using my “Activity New Intent with Arguments” template. I type ania
, the abbreviation I assigned to it, then hit <tab>
so Android Studio expands the template, and then I type these characters: String<tab><tab>scannerId<tab>
. I end up with this code:
public class ScannerActivity extends SingleFragmentActivity {
private static final String SCANNER_ID = "ScannerActivity.SCANNER_ID";
public static Intent newIntent(Context context, String scannerId) {
Intent intent = new Intent(context, ScannerActivity.class);
intent.putExtra(SCANNER_ID, scannerId);
return intent;
}
@Override
protected Fragment getFragment() {
String scannerId = getIntent().getStringExtra(SCANNER_ID);
return ScannerFragment.newInstance(scannerId);
}
}
I have another template, “Fragment New Instance with Arguments.” I type the abbreviation I assigned to the template, fnia
, then <tab>
, and get the expanded template. Then I type the same sequence of characters as for the ania
template: String<tab><tab>scannerId<tab>
. This is the result:
public class ScannerFragment extends Fragment {
private static final String SCANNER_ID = "ScannerFragment.SCANNER_ID";
private String mScannerId;
public static ScannerFragment newInstance(String scannerId) {
ScannerFragment fragment = new ScannerFragment();
Bundle args = new Bundle();
args.putString(SCANNER_ID, scannerId);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mScannerId = getArguments().getString(SCANNER_ID);
}
}
Not too bad for just under 30 keystrokes.
Creating Templates
There are two parts to live templates. One is the template itself and the other is the definition of the variables. This is my ania
live template:
private static final String $EXTRA_PARAM$ = "$CLASS_NAME$.$EXTRA_PARAM$";
public static Intent newIntent(Context context, $EXTRA_CLASS$ $EXTRA_VAR$) {
Intent intent = new Intent(context, $CLASS_NAME$.class);
intent.putExtra($EXTRA_PARAM$, $EXTRA_VAR$);$END$
return intent;
}
@Override
protected Fragment getFragment() {
$EXTRA_CLASS$ $EXTRA_VAR$ = getIntent().get$EXTRA_CLASS$Extra($EXTRA_PARAM$);
return $FRAGMENT_CLASS$.newInstance($EXTRA_VAR$);
}
Note that variables are deliniated by the $
symbol. Normally, each variable is what you need to type in. If a variable appears in multiple places, all of them are updated simultaneously as you type. It’s possible to customize these variables and even to automatically set their values based on other variables.
For example, $CLASS_NAME$
is defined as expression className
, which evaluates to the name of the current class. Here’s the full list of definitions:
Name | Expression | Default Value | Skip if Defined |
---|---|---|---|
EXTRA_CLASS |
typeOfVariable(VAR) |
[ ] | |
EXTRA_VAR |
suggestVariableName |
[ ] | |
CLASS_NAME |
className |
[x] | |
EXTRA_PARAM |
capitalizeAndUnderscore(EXTRA_VAR) |
[x] | |
FRAGMENT_CLASS |
groovyScript("_1.replaceAll('Activity','Fragment')", CLASS_NAME) |
[x] |
Three of the variables are marked “Skip if defined,” so I don’t need to type them; their names are derived from what I have already typed. I can even use groovyScript
to evaluate expressions beyond the fairly rich predefined set.
As I noted earlier, $END$
controls where your cursor will be once you’re done filling out the template. In this example, I want to put it inside the newIntent
method just before the return
statement, so that I can customize the Intent
object further. For example, I could add flags or more extras.
The fnia
template is very similar:
private static final String $ARG_PARAM$ = "$CLASS_NAME$.$ARG_PARAM$";
private $ARG_CLASS_DITTO$ m$INST_VAR$;
public static $CLASS_NAME$ newInstance($ARG_CLASS$ $ARG_VAR$) {
$CLASS_NAME$ fragment = new $CLASS_NAME$();
Bundle args = new Bundle();
args.put$ARG_CLASS$($ARG_PARAM$, $ARG_VAR$);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
m$INST_VAR$ = getArguments().get$ARG_CLASS$($ARG_PARAM$);
}
I had to use a little trick in this template. I created a special variable, $ARG_CLASS_DITTO$
. that’s a copy of the $ARG_CLASS$
variable. The reason I duplicated them is to force the cursor to start at the type of the parameter of the newInstance
method. If I didn’t do this, the cursor would first jump to the type of the instance variable, then to the name of the parameter.
Thanks to live templates, I’ve reduced the amount of typing I have to do when creating new Activities and Fragments. Of course, there are many other situations where Live Templates would come in handy as well. I’m sure lots of you have your own productivity tips and examples of Live Templates, so please feel free to share with your fellow developers in the comments!