Problem
Task description
Make an quiz-app based upon a topic you feel familiar with!
Following requirements
-
Has at least four questions.
-
Following controls are all used at least one time: Button, TextView, EditText, CheckBoxes, RadioButtons.
-
At least one CheckBox-Group uses multi-select.
-
It’s got to have a Submit-Button and a Reset-Button, which empties all controls.
Here’s my Java source-code …
package de.n_or.quizapp;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void startEvaluation(View view) {
String[] answers = evaluateGui();
int result = evaluateQuiz(answers);
toastResult(result);
}
public String[] evaluateGui() {
String[] ret = new String[5];
EditText editTextQuestion1 = findViewById(R.id.question_1);
CheckBox checkBoxQuestion2Greece = findViewById(R.id.question_2_Greece);
CheckBox checkBoxQuestion2Burma = findViewById(R.id.question_2_Burma);
CheckBox checkBoxQuestion2Luxembourg = findViewById(R.id.question_2_Luxembourg);
Boolean answerQuestion2 = false;
if (checkBoxQuestion2Greece.isChecked() == true && checkBoxQuestion2Burma.isChecked() == false && checkBoxQuestion2Luxembourg.isChecked() == true) {
answerQuestion2 = true;
}
CheckBox checkBoxQuestion4Capital = findViewById(R.id.question_4_capital);
CheckBox checkBoxQuestion4Hessia = findViewById(R.id.question_4_hessia);
CheckBox checkBoxQuestion4Bavaria = findViewById(R.id.question_4_bavaria);
Boolean answerQuestion4 = false;
Boolean capital = checkBoxQuestion4Capital.isChecked();
Boolean hessia = checkBoxQuestion4Hessia.isChecked();
Boolean bavaria = checkBoxQuestion4Bavaria.isChecked();
if (capital == false && hessia == false && bavaria == true) {
answerQuestion4 = true;
}
ret[0] = editTextQuestion1.getText().toString().toLowerCase();
ret[1] = Boolean.toString(answerQuestion2);
ret[2] = evaluateRadioGroup(R.id.radio_group_question_3).toLowerCase();
ret[3] = Boolean.toString(answerQuestion4);
ret[4] = evaluateRadioGroup(R.id.radio_group_question_5).toLowerCase();
return ret;
}
public int evaluateQuiz(String[] answers) {
int result = 0;
String[] correctAnswers = {"paris", "true", "south", "true", "germany"};
for (int i = 0; i < correctAnswers.length; i++) {
if (answers[i].equals(correctAnswers[i])) {
result++;
}
}
return result;
}
public void toastResult(int result) {
String message = result + " out of 5. ";
if (result == 0) {
message += "Poor luck.";
} else if (result == 1) {
message += "You could do better.";
} else if (result == 2) {
message += "Quite nice.";
} else if (result == 3) {
message += "Really nice.";
} else if (result == 4) {
message += "Great!";
} else if (result == 5) {
message += "Absolutely awesome!";
}
Toast reportResult = Toast.makeText(getApplicationContext(), message,
Toast.LENGTH_SHORT);
reportResult.show();
}
private String evaluateRadioGroup(int id) {
RadioGroup radioGroupQuestion;
RadioButton radioButtonQuestion;
radioGroupQuestion = findViewById(id);
int radioButtonId = radioGroupQuestion.getCheckedRadioButtonId();
radioButtonQuestion = findViewById(radioButtonId);
if (radioButtonQuestion == null) {
return "";
}
return (String)radioButtonQuestion.getText();
}
public void reset(View view) {
EditText editText = findViewById(R.id.question_1);
editText.setText("");
CheckBox checkBox = findViewById(R.id.question_2_Greece);
checkBox.setChecked(false);
checkBox = findViewById(R.id.question_2_Burma);
checkBox.setChecked(false);
checkBox = findViewById(R.id.question_2_Luxembourg);
checkBox.setChecked(false);
RadioGroup radioGroup = findViewById(R.id.radio_group_question_3);
radioGroup.clearCheck();
checkBox = findViewById(R.id.question_4_capital);
checkBox.setChecked(false);
checkBox = findViewById(R.id.question_4_hessia);
checkBox.setChecked(false);
checkBox = findViewById(R.id.question_4_bavaria);
checkBox.setChecked(false);
radioGroup = findViewById(R.id.radio_group_question_5);
radioGroup.clearCheck();
}
}
The XML for the layout …
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns_android="http://schemas.android.com/apk/res/android"
xmlns_tools="http://schemas.android.com/tools"
android_layout_width="match_parent"
android_layout_height="match_parent"
tools_context="de.n_or.quizapp.MainActivity">
<ScrollView
android_layout_width="match_parent"
android_layout_height="match_parent"
android_layout_alignParentTop="true"
android_layout_centerHorizontal="true"
android_layout_marginTop="0dp">
<LinearLayout
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_orientation="vertical">
<TextView
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_layout_marginBottom="4dp"
android_text="@string/sub_header"
android_textAlignment="center"
android_textSize="22sp" />
<TextView
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_layout_marginBottom="12dp"
android_layout_marginLeft="16dp"
android_layout_marginTop="20dp"
android_text="@string/question1"
android_textSize="16sp" />
<EditText
android_id="@+id/question_1"
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_layout_marginLeft="16dp" />
<TextView
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_layout_marginBottom="6dp"
android_layout_marginLeft="16dp"
android_layout_marginTop="20dp"
android_text="@string/question2"
android_textSize="16sp" />
<CheckBox
android_id="@+id/question_2_Greece"
android_layout_width="wrap_content"
android_layout_height="wrap_content"
android_layout_marginBottom="12dp"
android_layout_marginLeft="16dp"
android_layout_marginTop="0dp"
android_text="@string/checkbox_greece" />
<CheckBox
android_id="@+id/question_2_Burma"
android_layout_width="wrap_content"
android_layout_height="wrap_content"
android_layout_marginBottom="12dp"
android_layout_marginLeft="16dp"
android_layout_marginTop="0dp"
android_text="@string/checkbox_burma" />
<CheckBox
android_id="@+id/question_2_Luxembourg"
android_layout_width="wrap_content"
android_layout_height="wrap_content"
android_layout_marginBottom="12dp"
android_layout_marginLeft="16dp"
android_layout_marginTop="0dp"
android_text="@string/checkbox_luxembourg" />
<TextView
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_layout_marginBottom="6dp"
android_layout_marginLeft="16dp"
android_layout_marginTop="20dp"
android_text="@string/question3"
android_textSize="16sp" />
<RadioGroup
android_id="@+id/radio_group_question_3"
android_layout_width="wrap_content"
android_layout_height="wrap_content"
android_orientation="vertical">
<RadioButton
android_id="@+id/question_3_north"
android_layout_width="wrap_content"
android_layout_height="wrap_content"
android_layout_marginBottom="0dp"
android_layout_marginLeft="16dp"
android_layout_marginTop="4dp"
android_text="@string/north" />
<RadioButton
android_id="@+id/question_3_east"
android_layout_width="wrap_content"
android_layout_height="wrap_content"
android_layout_marginBottom="0dp"
android_layout_marginLeft="16dp"
android_layout_marginTop="2dp"
android_text="@string/east" />
<RadioButton
android_id="@+id/question_3_south"
android_layout_width="wrap_content"
android_layout_height="wrap_content"
android_layout_marginBottom="0dp"
android_layout_marginLeft="16dp"
android_layout_marginTop="2dp"
android_text="@string/south" />
<RadioButton
android_id="@+id/question_3_west"
android_layout_width="wrap_content"
android_layout_height="wrap_content"
android_layout_marginBottom="6dp"
android_layout_marginLeft="16dp"
android_layout_marginTop="2dp"
android_text="@string/west" />
</RadioGroup>
<TextView
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_layout_marginBottom="6dp"
android_layout_marginLeft="16dp"
android_layout_marginTop="20dp"
android_text="@string/question4"
android_textSize="16sp" />
<CheckBox
android_id="@+id/question_4_capital"
android_layout_width="wrap_content"
android_layout_height="wrap_content"
android_layout_marginBottom="12dp"
android_layout_marginLeft="16dp"
android_layout_marginTop="0dp"
android_text="@string/munich_question_1" />
<CheckBox
android_id="@+id/question_4_bavaria"
android_layout_width="wrap_content"
android_layout_height="wrap_content"
android_layout_marginBottom="12dp"
android_layout_marginLeft="16dp"
android_layout_marginTop="0dp"
android_text="@string/munich_question_3" />
<CheckBox
android_id="@+id/question_4_hessia"
android_layout_width="wrap_content"
android_layout_height="wrap_content"
android_layout_marginBottom="12dp"
android_layout_marginLeft="16dp"
android_layout_marginTop="0dp"
android_text="@string/munich_question_2" />
<TextView
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_layout_marginBottom="6dp"
android_layout_marginLeft="16dp"
android_layout_marginTop="20dp"
android_text="@string/question5"
android_textSize="16sp" />
<RadioGroup
android_id="@+id/radio_group_question_5"
android_layout_width="wrap_content"
android_layout_height="wrap_content"
android_orientation="vertical">
<RadioButton
android_id="@+id/question_5_germany"
android_layout_width="wrap_content"
android_layout_height="wrap_content"
android_layout_marginBottom="0dp"
android_layout_marginLeft="16dp"
android_layout_marginTop="4dp"
android_text="@string/germany" />
<RadioButton
android_id="@+id/question_5_poland"
android_layout_width="wrap_content"
android_layout_height="wrap_content"
android_layout_marginBottom="0dp"
android_layout_marginLeft="16dp"
android_layout_marginTop="2dp"
android_text="@string/poland" />
<RadioButton
android_id="@+id/question_5_denmark"
android_layout_width="wrap_content"
android_layout_height="wrap_content"
android_layout_marginBottom="22dp"
android_layout_marginLeft="16dp"
android_layout_marginTop="2dp"
android_text="@string/denmark" />
</RadioGroup>
<Button
android_id="@+id/evaluate"
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_layout_marginBottom="22dp"
android_layout_marginLeft="16dp"
android_layout_marginRight="16dp"
android_onClick="startEvaluation"
android_text="@string/evaluate_button" />
<Button
android_id="@+id/reset"
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_layout_marginLeft="16dp"
android_layout_marginRight="16dp"
android_onClick="reset"
android_text="@string/reset_button"
android_textColor="#ff0033"
android_textStyle="bold" />
</LinearLayout>
</ScrollView>
</LinearLayout>
Hyperlink to my GitHub-Repository.
What would you have done different and why?
Looking forward to reading for comments and answers.
Solution
tldr: you don’t use object orientated programming! the following answer only tells you how to use objects
UI / XML
I would advise you to split your layout into different sub-layouts, so you can re-use the layouts. thus you can easily extend your app in the future.
CODE
I think it would be a good idea to use Question
-object. Maybe you would be able to create a factory that create these objects for you – just think of it?
Question capitals = questionFactory.createQuestion(
QuestionType.MultiChoice,
new boolean[]{true, false, true},
new int[]{R.string.question_2_Greece,
R.string.question_2_Burma,
R.string.question_2_Luxembourg}
);
that would make it easy for you to create any new questions in a simple way. And if you don’t know how to do that you can at least write a simple methods to create the Question
-objects Question question = createQuestion(...);
and once this is done it would be easy to use this Question
-object for your layout, the layout you add dynamical, not hardcoded in your xml-layout.
View view = findViewById(R.id.scrollview); //FIXME set an ID in your layout
View multiChoiceView = createMultiChoiceView(capitals);
view.addView(multiChoiceView);
you can hence create the sublayout programmatical, if you use the inflater
View multiChoiceView = View.inflate(context, multiChoiceView, yourLinearLayout);
when you creat the layout you can ‘on-the-fly’ set the values and bind the gui to the model. (see this explanation for the different approaches on model/view)
and once this is done you can easily get to your results. Results should be represented as well as an object not a String[]
, as done in evaluateGui
. This way you’re abusing the String[] to represent your results.
private List<Question> questions = ... //see above
private Result validateQuestions(){
Result result = new Result();
for (Question question: questions){
result.addScores(question.getScores());
}
return result;
}
to validate the result you could also use an enum type instead of counting points.
enum Rating {POOR, MEDICRATE, GOOD, PERFECT};//TODO make a nice toString
public void toastResult(Result result) {
int scores = result.getScores();
int amount = result.getAmountQuestions();
Rating rating = result.getRating();
String message = MessageFormat.format("you had {0} of {1} - your rating is {2}", scores, amount, rating);
Toast.makeText(getApplicationContext(), message,
Toast.LENGTH_SHORT).show();