i'm trying to make a multiple choice quiz game, at the moment the SQLite data base is set up (i think) and the data for the questions are stored. However, when i try to display the question onto the screen the question does not show. i have no idea what the problem is.
Error
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.ninjanumbers, PID: 1603 java.lang.NullPointerException: Attempt to invoke virtual method 'int com.ninjanumbers.Question.getAnswerNum()' on a null object reference at com.ninjanumbers.NumGame.checkAnswer(NumGame.java:129) at com.ninjanumbers.NumGame.access$400(NumGame.java:19) at com.ninjanumbers.NumGame$1.onClick(NumGame.java:78) at android.view.View.performClick(View.java:7448) at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1119) at android.view.View.performClickInternal(View.java:7425) at android.view.View.access$3600(View.java:810) at android.view.View$PerformClick.run(View.java:28305) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7656) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
NumGame.java
public class NumGame extends AppCompatActivity {
// defining variables
private TextView textViewQuestion;
private TextView textViewScore;
private TextView textViewQuestionCount;
private TextView textViewCountDown;
private RadioGroup rbGroup;
private RadioButton rb1;
private RadioButton rb2;
private RadioButton rb3;
private Button btnConfirm;
private ColorStateList textColorDefaultRb; // default text colour for radio button
private List<Question> questionsList;
private int questionCounter;
private int questionCountTotal;
private Question currentQuestion;
private int score;
private boolean answered;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_num_game);
// initializing variables
textViewQuestion = findViewById(R.id.txtQuestionDisplay);
textViewScore = findViewById(R.id.txtScore);
textViewQuestionCount = findViewById(R.id.txtQuestionTrack);
textViewCountDown = findViewById(R.id.txtTime);
rbGroup = findViewById(R.id.radioGroup);
rb1 = findViewById(R.id.radioButton1);
rb2 = findViewById(R.id.radioButton2);
rb3 = findViewById(R.id.radioButton3);
btnConfirm = findViewById(R.id.btnConfirm);
textColorDefaultRb = rb1.getTextColors(); // gets colour of the radio button
// creates a new instance of the data retriever for the data base data
QuizDbHelper dbHelper = new QuizDbHelper(this);
// this line also creates the data base when called for the first time
questionsList = dbHelper.getAllQuestions();
questionCountTotal = questionsList.size();
Collections.shuffle(questionsList); // randomises question order
//textViewQuestion.setText("hello"); // ToDo: fix the display text bug
showNextQuestion();
btnConfirm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!answered){
// handles an answered question (checked radio button)
if (rb1.isChecked() || rb2.isChecked() || rb3.isChecked()){
checkAnswer();
// handles an unanswered question
} else {
Toast.makeText(NumGame.this, "Please select an answer.", Toast.LENGTH_SHORT).show();
}
} else {
showNextQuestion();
}
}
});
}
// logic for displaying question
private void showNextQuestion() {
// resets the colour of the radio buttons
rb1.setTextColor(textColorDefaultRb);
rb2.setTextColor(textColorDefaultRb);
rb3.setTextColor(textColorDefaultRb);
// unselects buttons
rbGroup.clearCheck();
// starts at 0 and increments each time a question is used from the list
if (questionCounter < questionCountTotal) {
currentQuestion = questionsList.get(questionCounter);
// updates the screen and displays the next question and options
textViewQuestion.setText(currentQuestion.getQuestion());
rb1.setText(currentQuestion.getOption1());
rb2.setText(currentQuestion.getOption2());
rb3.setText(currentQuestion.getOption3());
// increments the question count
questionCounter ++;
textViewQuestionCount.setText("Question: " + questionCounter + "/" + questionCountTotal);
answered = false;
btnConfirm.setText("Confirm");
} else {
//finishQuiz();
textViewQuestion.setText("hello");
}
}
// checks if a answer is correct or not
private void checkAnswer() {
answered = true;
RadioButton rbSelected = findViewById(rbGroup.getCheckedRadioButtonId());
int answerNum = rbGroup.indexOfChild(rbSelected) + 1;
if (answerNum == currentQuestion.getAnswerNum()) {
score++;
textViewScore.setText("Score: " + score);
}
showSolution();
}
private void showSolution() {
// sets radio buttons to red
rb1.setTextColor(Color.RED);
rb2.setTextColor(Color.RED);
rb3.setTextColor(Color.RED);
// displaying the correct answer
switch (currentQuestion.getAnswerNum()){
case 1:
rb1.setTextColor(Color.GREEN);
textViewQuestion.setText("Answer 1 is correct!");
break;
case 2:
rb2.setTextColor(Color.GREEN);
textViewQuestion.setText("Answer 2 is correct!");
break;
case 3:
rb3.setTextColor(Color.GREEN);
textViewQuestion.setText("Answer 3 is correct!");
break;
}
if (questionCounter < questionCountTotal){
btnConfirm.setText("Next");
} else {
btnConfirm.setText("Finish");
}
}
QuizDbHelper.java
public class QuizDbHelper extends SQLiteOpenHelper{
// defines constants
private static final String DATABASE_NAME = "NumberNinjas.db";
private static final int DATABASE_VERSION = 1;
// holds reference to the data base
private SQLiteDatabase db;
public QuizDbHelper(Context context) {
super(context,DATABASE_NAME, null, DATABASE_VERSION);
}
// creates the table
@Override
public void onCreate(SQLiteDatabase db) {
this.db = db;
// SQL commands to create table
final String SQL_CREATE_QUESTIONS_TABLE = "CREATE TABLE " +
QuestionTable.TABLE_NAME + " ( " +
QuestionTable._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + // bug was here, game crashed because the sql creary was wrong and when the "_id" value was added the "Integer" query was concatenated with it
QuestionTable.COLUMN_QUESTION + " TEXT, " +
QuestionTable.COLUMN_OPTION1 + " TEXT, " +
QuestionTable.COLUMN_OPTION2 + " TEXT, " +
QuestionTable.COLUMN_OPTION3 + " TEXT, " +
QuestionTable.COLUMN_ANSWER_NUM + " INTEGER" +
")";
db.execSQL(SQL_CREATE_QUESTIONS_TABLE);
// calls the function that fills the table with data
fillQuestionsTable();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// deletes database and creates it again if the table already exists
db.execSQL("DROP TABLE IF EXISTS " + QuestionTable.TABLE_NAME);
onCreate(db);
}
// fills the table with data
/***
* This is where the questions are added.
*
* future improvements can be to make these questions randomly generated
* instead of hard coded questions
*/
private void fillQuestionsTable() {
Question q1 = new Question("A is Correct", "A", "B", "C",1);
// calls add questions function and adds a question
addQuestion(q1);
Question q2 = new Question("B is Correct", "A", "B", "C",2);
// calls add questions function and adds a question
addQuestion(q2);
Question q3 = new Question("C is Correct", "A", "B", "C",3);
// calls add questions function and adds a question
addQuestion(q3);
Question q4 = new Question("A is Correct again", "A", "B", "C",1);
// calls add questions function and adds a question
addQuestion(q4);
Question q5 = new Question("B is Correct again", "A", "B", "C",2);
// calls add questions function and adds a question
addQuestion(q5);
}
private void addQuestion(Question question) {
// creates an new instance of the content value class and sets its identifier to cv
ContentValues cv = new ContentValues();
// retrieves the data and implements it to the data base
cv.put(QuestionTable.COLUMN_QUESTION, question.getQuestion());
cv.put(QuestionTable.COLUMN_OPTION1, question.getOption1());
cv.put(QuestionTable.COLUMN_OPTION2, question.getOption2());
cv.put(QuestionTable.COLUMN_OPTION3, question.getOption3());
cv.put(QuestionTable.COLUMN_ANSWER_NUM, question.getAnswerNum());
db.insert(QuestionTable.TABLE_NAME, null, cv);
}
// retrieves the data of the database
public List<Question> getAllQuestions() {
List<Question> questionList = new ArrayList<>();
db = getReadableDatabase();
// creates a entry point for the system to retrieve data
Cursor c = db.rawQuery("SELECT * FROM " + QuestionTable.TABLE_NAME, null);
// reading the table and allocating data to question class objects
if (c.moveToFirst()) {
do {
Question question = new Question();
question.setQuestion(c.getString(c.getColumnIndex(QuestionTable.COLUMN_QUESTION)));
question.setOption1(c.getString(c.getColumnIndex(QuestionTable.COLUMN_OPTION1)));
question.setOption2(c.getString(c.getColumnIndex(QuestionTable.COLUMN_OPTION2)));
question.setOption3(c.getString(c.getColumnIndex(QuestionTable.COLUMN_OPTION3)));
question.setAnswerNum(c.getInt(c.getColumnIndex(QuestionTable.COLUMN_ANSWER_NUM)));
// creates question object for each entry in the database and adds them to the question list
questionList.add(question);
} while (c.moveToNext());
}
c.close();
return questionList;
}
sorry for the large amount of code i just have no idea what is wrong with it.