Here is a clean, complete template for a multiple-choice quiz using standard Android Java and an XML layout. It features custom styling for the options using a RadioGroup and handles the question state dynamically.
1. The Layout (activity_main.xml)
This UI uses a TextView for the question, a RadioGroup to hold the choices (ensuring only one can be selected at a time), and a Button to submit the answer.
XML
<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_width"android:layout_height="match_parent"android:orientation="vertical"android:padding="24dp"android:gravity="center_vertical"><!-- Question Counter --><TextViewandroid:id="@+id/tv_question_number"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Question 1 of 3"android:textSize="14sp"android:textColor="#757575"android:layout_marginBottom="8dp" /><!-- The Question --><TextViewandroid:id="@+id/tv_question"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="What is the capital city of France?"android:textSize="22sp"android:textStyle="bold"android:textColor="#212121"android:layout_marginBottom="24dp" /><!-- Options Container --><RadioGroupandroid:id="@+id/rg_options"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginBottom="32dp"><RadioButtonandroid:id="@+id/rb_option1"android:layout_width="match_parent"android:layout_height="wrap_content"android:padding="16dp"android:layout_marginBottom="8dp"android:text="London"android:textSize="16sp" /><RadioButtonandroid:id="@+id/rb_option2"android:layout_width="match_parent"android:layout_height="wrap_content"android:padding="16dp"android:layout_marginBottom="8dp"android:text="Berlin"android:textSize="16sp" /><RadioButtonandroid:id="@+id/rb_option3"android:layout_width="match_parent"android:layout_height="wrap_content"android:padding="16dp"android:layout_marginBottom="8dp"android:text="Paris"android:textSize="16sp" /><RadioButtonandroid:id="@+id/rb_option4"android:layout_width="match_parent"android:layout_height="wrap_content"android:padding="16dp"android:layout_marginBottom="8dp"android:text="Madrid"android:textSize="16sp" /></RadioGroup><!-- Action Button --><Buttonandroid:id="@+id/btn_submit"android:layout_width="match_parent"android:layout_height="56dp"android:text="Submit Answer"android:textSize="16sp" /></LinearLayout>
2. The Logic (MainActivity.java)
This class manages the quiz state, validates whether an option was chosen, tallies the score, and handles advancing to the next question.
Java
package com.example.quizapp;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
publicclassMainActivityextendsAppCompatActivity{
private TextView tvQuestionNumber, tvQuestion;
private RadioGroup rgOptions;
private RadioButton rbOption1, rbOption2, rbOption3, rbOption4;
private Button btnSubmit;
// Quiz Data Arraysprivatefinal String[] questions = {
"What is the capital city of France?",
"Which planet is known as the Red Planet?",
"What is the largest mammal on Earth?"
};
privatefinal String[][] options = {
{"London", "Berlin", "Paris", "Madrid"},
{"Earth", "Mars", "Jupiter", "Saturn"},
{"Elephant", "Blue Whale", "Giraffe", "Orca"}
};
// Index tracking for the correct answers (0-indexed)privatefinalint[] correctAnswers = {2, 1, 1}; // Paris, Mars, Blue Whaleprivateint currentQuestionIndex = 0;
privateint score = 0;
@Overrideprotectedvoid Bundle) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initialize UI Elements
tvQuestionNumber = findViewById(R.id.tv_question_number);
tvQuestion = findViewById(R.id.tv_question);
rgOptions = findViewById(R.id.rg_options);
rbOption1 = findViewById(R.id.rb_option1);
rbOption2 = findViewById(R.id.rb_option2);
rbOption3 = findViewById(R.id.rb_option3);
rbOption4 = findViewById(R.id.rb_option4);
btnSubmit = findViewById(R.id.btn_submit);
// Load the first question
loadQuestion();
// Handle button clicks
btnSubmit.setOnClickListener(new View.OnClickListener() {
@OverridepublicvoidonClick(View v){
int selectedId = rgOptions.getCheckedRadioButtonId();
// 1. Validation check: Ensure they picked an optionif (selectedId == -1) {
Toast.makeText(MainActivity.this, "Please select an answer", Toast.LENGTH_SHORT).show();
return;
}
// 2. Identify which button was clicked
RadioButton selectedRadioButton = findViewById(selectedId);
int selectedAnswerIndex = rgOptions.indexOfChild(selectedRadioButton);
// 3. Check if the answer is correctif (selectedAnswerIndex == correctAnswers[currentQuestionIndex]) {
score++;
Toast.makeText(MainActivity.this, "Correct!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, "Wrong Answer!", Toast.LENGTH_SHORT).show();
}
// 4. Advance or show results
currentQuestionIndex++;
if (currentQuestionIndex < questions.length) {
loadQuestion();
} else {
showResults();
}
}
});
}
privatevoidloadQuestion(){
// Reset the selection container
rgOptions.clearCheck();
// Update Text
String progressText = "Question " + (currentQuestionIndex + 1) + " of " + questions.length;
tvQuestionNumber.setText(progressText);
tvQuestion.setText(questions[currentQuestionIndex]);
// Update Options
rbOption1.setText(options[currentQuestionIndex][0]);
rbOption2.setText(options[currentQuestionIndex][1]);
rbOption3.setText(options[currentQuestionIndex][2]);
rbOption4.setText(options[currentQuestionIndex][3]);
// If it's the final question, change button textif (currentQuestionIndex == questions.length - 1) {
btnSubmit.setText("Finish Quiz");
}
}
privatevoidshowResults(){
// Disable choices and update UI to show score
tvQuestionNumber.setText("Quiz Completed");
tvQuestion.setText("Your final score is: " + score + " / " + questions.length);
rgOptions.setVisibility(View.GONE);
// Turn the button into a restart button
btnSubmit.setText("Restart Quiz");
btnSubmit.setOnClickListener(new View.OnClickListener() {
@OverridepublicvoidonClick(View v){
// Reset state parameters
currentQuestionIndex = 0;
score = 0;
rgOptions.setVisibility(View.VISIBLE);
btnSubmit.setText("Submit Answer");
// Re-wire original behavior
recreate();
}
});
}
}
How the mechanics work under the hood:
rgOptions.clearCheck(): It is critical to clear the previous selection before loading a new question. Otherwise, if a user selected option 3 on question 1, option 3 will remain checked when question 2 displays.
rgOptions.indexOfChild(...): This helper maps the active RadioButton directly to its integer index inside the group layout ($0, 1, 2,$ or $3$). This allows for quick math comparisons against the correctAnswers index array without needing to parse the actual string labels.