Buttons, CheckBox & RadioButton
Starting with this lesson, we build one running example across the rest of this track: RecipeBox, a recipe-manager app. Its core data class looks like this, and we will reuse it in every upcoming lesson:
// Recipe.java
public class Recipe {
public String id;
public String title;
public String ingredients;
public String steps;
public String photoUri;
public String category;
public int prepMinutes;
public boolean isFavorite;
public String difficulty; // "Easy", "Medium", "Hard"
}
Button, CheckBox and RadioButton are the three most common widgets for letting a user act on or choose between options. Every one of them is a subclass of TextView under the hood, so anything you already know about android:text or styling text applies here too.
Button: Triggering an Action
A Button (or its Material replacement, com.google.android.material.button.MaterialButton) fires a single event when tapped. In RecipeBox, the "add/edit recipe" screen ends with a Save button:
<Button
android:id="@+id/btnSaveRecipe"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Save Recipe" />
The classic way to react to a tap is an anonymous View.OnClickListener:
Button btnSaveRecipe = findViewById(R.id.btnSaveRecipe);
btnSaveRecipe.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Recipe recipe = buildRecipeFromForm();
saveRecipeToDatabase(recipe);
Toast.makeText(RecipeFormActivity.this, "Recipe saved", Toast.LENGTH_SHORT).show();
}
});
Since Java 8, most Android projects target a level that supports lambdas, and View.OnClickListener is a functional interface (a single abstract method, onClick), so it can be written far more compactly:
btnSaveRecipe.setOnClickListener(v -> {
Recipe recipe = buildRecipeFromForm();
saveRecipeToDatabase(recipe);
Toast.makeText(this, "Recipe saved", Toast.LENGTH_SHORT).show();
});
- Both forms register the same callback; the lambda is just less boilerplate for a single method.
- Inside the anonymous class, this refers to the listener, so the enclosing Activity is referenced as RecipeFormActivity.this. Inside a lambda there is no new this, so plain this already means the Activity.
- Prefer lambdas for new code in this current, modern style of Android development — they read cleaner and are what you'll see in most real-world Java Android codebases today.
CheckBox: Independent On/Off Options
A CheckBox represents a choice that is independent of any other choice on the screen — turning it on or off doesn't affect anything else. RecipeBox uses one on the recipe-detail screen to let the user mark a recipe as a favorite:
<CheckBox
android:id="@+id/cbFavorite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Mark as Favorite"
android:checked="false" />
CheckBox cbFavorite = findViewById(R.id.cbFavorite);
cbFavorite.setChecked(recipe.isFavorite);
cbFavorite.setOnCheckedChangeListener((buttonView, isChecked) -> {
recipe.isFavorite = isChecked;
favoriteRepository.update(recipe);
});
RadioButton & RadioGroup: Mutually Exclusive Choices
When only one of several options can be selected at a time, use RadioButton widgets wrapped in a RadioGroup. RecipeBox uses this for picking a recipe's difficulty level:
<RadioGroup
android:id="@+id/rgDifficulty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioButton
android:id="@+id/rbEasy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Easy"
android:checked="true" />
<RadioButton
android:id="@+id/rbMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Medium" />
<RadioButton
android:id="@+id/rbHard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hard" />
</RadioGroup>
Reading which one is checked, once the user taps Save:
RadioGroup rgDifficulty = findViewById(R.id.rgDifficulty);
btnSaveRecipe.setOnClickListener(v -> {
int checkedId = rgDifficulty.getCheckedRadioButtonId();
RadioButton checkedButton = findViewById(checkedId);
recipe.difficulty = checkedButton.getText().toString();
saveRecipeToDatabase(recipe);
});
- Only one RadioButton inside the same RadioGroup can be checked; tapping a different one automatically unchecks the previous choice.
- getCheckedRadioButtonId() returns the id of the selected button, or -1 if none is checked.
- Setting android:checked="true" on one RadioButton in the XML gives you a sensible default ("Easy") the first time the form opens.
android:onClick — An Older Alternative
Older Android code sometimes wires a click straight from XML using android:onClick="methodName", which calls a public, no-argument, void method with that name on the hosting Activity:
<Button
android:id="@+id/btnSaveRecipe"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Save Recipe"
android:onClick="onSaveRecipeClicked" />
public void onSaveRecipeClicked(View view) {
saveRecipeToDatabase(buildRecipeFromForm());
}
Styling With Material Components
All three widgets have Material Design counterparts — MaterialButton, MaterialCheckBox and MaterialRadioButton — that apply consistent theming, ripple effects, and elevation automatically. The Java APIs above (click listeners, checked-state listeners, RadioGroup) work identically whether you use the plain widgets or their Material versions. See Material Components (Java) for how to switch a layout over and pick up Material styling with minimal XML changes.