I am making a quiz app just for the experience and i have a main questions page which says the question number ,question and the options...if the answer is wrong ,it gives a 4 hours wait time, if its correct then 24 hours for the next question.. i am retrieving the question number ,question ,options and the answer from an existing database that i have linked using DatabaseHelper Class.The first time it correctly takes the values from the database.
My concern is that when i return to main questions page from 24hour wait , it does not again refresh the textviews and hence shows me the default text i kept in the xml file.
i know that when i use intent to return to main page , it goes on onRestart() then onStart() or onResume() and not on onCreate() but i tried everything i could find on stackoverflow and youtube.
So i figure its something specially with my code, as it worked for others.. Please help me if anyone can, as i said i tried alot of things but maybe i dint implement them correctly .
The Main questions page code and screenshots:
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;
import android.database.Cursor;
import android.database.SQLException;
import java.io.IOException;
public class activityQuiz extends AppCompatActivity {
private RadioGroup radioGroup;
private RadioButton radioButton,option1,option2,option3,option4;
private Button submitBtn;
private String answer_text;
private TextView question_no,ques_text;
String table = "questions";
String[] columns = null;
String selection = "id =?";
String groupBy = null;
String having = null;
String orderBy = null;
Cursor c = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_quiz);
final Global globalVariable = (Global) getApplicationContext();
String[] selectionArgs = {String.valueOf(globalVariable.getQuestion_number())};
radioGroup = (RadioGroup) findViewById(R.id.radio_q);
submitBtn = (Button) findViewById(R.id.submit_btn);
question_no = (TextView) findViewById(R.id.question_number);
ques_text = (TextView) findViewById(R.id.tv3);
option1 = (RadioButton) findViewById(R.id.radio1);
option2 = (RadioButton) findViewById(R.id.radio2);
option3 = (RadioButton) findViewById(R.id.radio3);
option4 = (RadioButton) findViewById(R.id.radio4);
submitBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// get selected radio button from radioGroup
int selectedId = radioGroup.getCheckedRadioButtonId();
// find the radiobutton by returned id
radioButton = (RadioButton) findViewById(selectedId);
Toast.makeText(activityQuiz.this, radioButton.getText(), Toast.LENGTH_SHORT).show();
String selected = radioButton.getText().toString();
//if condition
if(selected.equals(answer_text)) {
finish();
globalVariable.setQuestion_number(globalVariable.getQuestion_number()+ 1);
Intent stud = new Intent(activityQuiz.this,activityCorrect.class);
startActivity(stud);
finish();
}
else
{
finish();
Intent stud = new Intent(activityQuiz.this, activityWrong.class);
startActivity(stud);
finish();
}
}
});
database_paste(selectionArgs);
}
/*protected void onResume() {
super.onResume();
this.onCreate(null);
}*/
private void database_paste(String[] selectionArgs)
{
DatabaseHelper myDbHelper = new DatabaseHelper(activityQuiz.this);
try {
myDbHelper.createDataBase();
} catch (IOException ioe) {
throw new Error("Unable to create database");
}
try {
myDbHelper.openDataBase();
} catch (SQLException sqle) {
throw sqle;
}
Toast.makeText(activityQuiz.this, "Success", Toast.LENGTH_SHORT).show();
c = myDbHelper.query(table, columns, selection, selectionArgs, groupBy, having, orderBy);
if (c.moveToFirst()) {
do {
question_no.setText(c.getString(0));
ques_text.setText(c.getString(1));
option1.setText(c.getString(2));
option2.setText(c.getString(3));
option3.setText(c.getString(4));
option4.setText(c.getString(5));
answer_text = c.getString(6);
Toast.makeText(activityQuiz.this,
"_id: " + c.getString(0) + "\n"+
"_answer" + c.getString(6),
Toast.LENGTH_LONG).show();
} while (c.moveToNext());
}
}
}
https://i.sstatic.net/8bwvE.png then i choose correct answer and after 24 hours back to main activity https://i.sstatic.net/hVmrP.png
Activity Correct class:
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import cn.iwgang.countdownview.CountdownView;
import cn.iwgang.countdownview.DynamicConfig;
public class activityCorrect extends AppCompatActivity {
CountdownView countview1;
TextView tv1 ;
Button nextQues;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_correct);
countview1 = (CountdownView) findViewById(R.id.countdownView1);
countview1.start(10000);
tv1 = (TextView) findViewById(R.id.tv1);
nextQues = (Button) findViewById(R.id.next_question);
countview1.setOnCountdownEndListener(new CountdownView.OnCountdownEndListener()
{
@Override
public void onEnd(CountdownView cv)
{
tv1.setText("Next Question is Ready for you");
nextQues.setVisibility(View.VISIBLE);
}
});
nextQues.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent stud = new Intent(activityCorrect.this,activityQuiz.class);
startActivity(stud);
finish();
}
});
}
}
UPDATE:
I tried using onResume() , the toast inside it is working but the activity textviews become default anyway.
I tried onRestart() but the after testing it with toast, i find that onRestart() method is not getting executed
@Override
protected void onRestart() {
super.onRestart();
Toast.makeText(activityQuiz.this,
"Restart is working",
Toast.LENGTH_LONG).show();
final Global globalVariable = (Global) getApplicationContext();
String[] selectionArgs = {String.valueOf(globalVariable.getQuestion_number())};
database_paste(selectionArgs);
}
UPDATE : GLOBAL variable class:
package com.example.nikko.mygift;
import android.app.Application;
public class Global extends Application{
private int main_screen_check = 0,question_number = 1;
public int getQuestion_number() {
return question_number; //Question index memory
}
public void setQuestion_number(int question_number) {
this.question_number = question_number;
}
public int getMain_screen_check() {
return main_screen_check; //Main page check
}
public void setMain_screen_check(int main_screen_check) {
this.main_screen_check = main_screen_check;
}
}
If I understand you question I think this is what you want to add as 'onResume' will be called when you return from the activity:-
@Override
protected void onResume() {
super.onResume();
String[] selectionArgs = {String.valueOf(globalVariable.getQuestion_number())};
c = myDbHelper.query(table, columns, selection, selectionArgs, groupBy, having, orderBy);
if (c.moveToFirst()) {
do {
question_no.setText(c.getString(0));
ques_text.setText(c.getString(1));
option1.setText(c.getString(2));
option2.setText(c.getString(3));
option3.setText(c.getString(4));
option4.setText(c.getString(5));
answer_text = c.getString(6);
Toast.makeText(activityQuiz.this,
"_id: " + c.getString(0) + "\n"+
"_answer" + c.getString(6),
Toast.LENGTH_LONG).show();
} while (c.moveToNext());
}
}
And move this from inside onRestart
to be a class variable (perhaps discard onRestart) :-
final Global globalVariable = (Global) getApplicationContext();
e.g. :-
public class activityQuiz extends AppCompatActivity {
private RadioGroup radioGroup;
private RadioButton radioButton,option1,option2,option3,option4;
private Button submitBtn;
private String answer_text;
private TextView question_no,ques_text;
final Global globalVariable = (Global) getApplicationContext();
....... rest of the code .....
Although it would probably make sense to create a specific method that gets the data and assigns it to the Views, this could then be called from onCreate
and onResume
with a single line.
I believe the issue you were having, is as I commented that the variable was not persistent. As such I'd suggest incorporating another table for question progress.
This new table would be relatively simply basically a link to the related question (the code below assumes that if a linked row exists, then the question has been answered). It has 3 columns _id, the link/reference to the question (contains the questions _id) and a status column (not used but could be used to indicate a state e.g. answered but incorrect).
As you save that the database with questions exists, I've made it so that the MainActivity always tries to create the progress table, so it would add the table.
I've not incoporated calling another activity. However, the submitQuestion
method in the mainActivity is where you'd do this, this is also where the answer is checked.
First the layout I used i.e. activity_main.xml, all this consists of is A TextView for the heading, A TextView for the Question (which will display Sorry there are no Questions ready yet when there are no questions left) 4 TextView with CheckBoxes for the answers (I've made it so that questions don't need 4 options but 4 is the max) and finally a SUBMIT button.
<?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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="mjt.so46111824.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Questions" />
<TextView
android:id="@+id/question"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/answer1_text"
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="match_parent" />
<CheckBox
android:id="@+id/answer1_checkbox"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/answer2_text"
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="match_parent" />
<CheckBox
android:id="@+id/answer2_checkbox"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/answer3_text"
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="match_parent" />
<CheckBox
android:id="@+id/answer3_checkbox"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/answer4_text"
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="match_parent" />
<CheckBox
android:id="@+id/answer4_checkbox"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent" />
</LinearLayout>
<Button
android:id="@+id/submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SUBMIT"/>
</LinearLayout>
class DBHelper extends SQLiteOpenHelper {
public static final String DBNAME = "questions";
public static final String TABLENAME = "questions";
public static final String IDCOLUMN = "_id";
public static final String QUESTIONCOLUMN = "question";
public static final String NUMBERCOLUMN = "number";
public static final String ANSWER1COLUMN = "answer1";
public static final String ANSWER2COLUMN = "answer2";
public static final String ANSWER3COLUMN = "answer3";
public static final String ANSWER4COLUMN = "answer4";
public static final String CORRECTCOLUMN = "correctanswer";
public static final String PROGRESSTABLENAME = "progress";
public static final String QUESTIONREFCOLUMN = "questionref";
public static final String QUESTIONSTATECOLUMN = "questionstate";
String crtsql;
DBHelper(Context context) {
super(context, DBNAME, null, 1);
this.getWritableDatabase();
}
@Override
public void onCreate(SQLiteDatabase db) {
crtsql = "CREATE TABLE IF NOT EXISTS " + TABLENAME + "(" +
IDCOLUMN + " INTEGER PRIMARY KEY, " +
QUESTIONCOLUMN + " TEXT, " +
NUMBERCOLUMN + " INTEGER, " +
ANSWER1COLUMN + " TEXT, " +
ANSWER2COLUMN + " TEXT, " +
ANSWER3COLUMN + " TEXT, " +
ANSWER4COLUMN + " TEXT, " +
CORRECTCOLUMN + " INTEGER " +
")";
db.execSQL(crtsql);
createProgresstable(db);
}
public void createProgresstable(SQLiteDatabase db) {
String crtsql = "CREATE TABLE IF NOT EXISTS " + PROGRESSTABLENAME + "(" +
IDCOLUMN + " INTEGER PRIMARY KEY, " +
QUESTIONREFCOLUMN + " INTEGER NOT NULL," +
QUESTIONSTATECOLUMN + "INTEGER DEFAULT 0" +
")";
db.execSQL(crtsql);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
public void insertQuestion(String question,
int number,
String answer1,
String answer2,
String answer3,
String answer4,
int correctanswer) {
if (correctanswer < 1 || correctanswer > 4) {
Log.d("QUESTIONS","Invalid Question - Correct Answer outside of range 1-4.");
return;
}
ContentValues cv = new ContentValues();
cv.put(QUESTIONCOLUMN,question);
cv.put(NUMBERCOLUMN,number);
cv.put(ANSWER1COLUMN,answer1);
cv.put(ANSWER2COLUMN,answer2);
cv.put(ANSWER3COLUMN,answer3);
cv.put(ANSWER4COLUMN,answer4);
cv.put(CORRECTCOLUMN,correctanswer);
this.getWritableDatabase().insert(TABLENAME,null,cv);
}
public int getRowCount() {
Cursor csr = this.getWritableDatabase().query(TABLENAME,null,null,null,null,null,null);
int rv = csr.getCount();
csr.close();
return rv;
}
public Cursor getQuestionRow(long questionid) {
String whereclause = IDCOLUMN + "=?";
String[] whereargs = {Long.toString(questionid)};
return this.getWritableDatabase().query(TABLENAME,
null,
whereclause,whereargs,
null,null,null);
}
public void insertProgress(Long questionid) {
ContentValues cv = new ContentValues();
cv.put(QUESTIONREFCOLUMN,questionid);
this.getWritableDatabase().insert(PROGRESSTABLENAME,null,cv);
}
public Cursor getProgressOfQuestion(long questionid) {
String whereclause = QUESTIONREFCOLUMN + "=?";
String[] whereargs = {Long.toString(questionid)};
return this.getWritableDatabase().query(PROGRESSTABLENAME,null,whereclause,whereargs,null,null,null
);
}
public void updateProgressStatus(long questionid,int newstatus) {
String whereclause = QUESTIONREFCOLUMN + "=?";
String[] wherargs = {Long.toString(questionid)};
ContentValues cv = new ContentValues();
cv.put(QUESTIONSTATECOLUMN,newstatus);
this.getWritableDatabase().update(PROGRESSTABLENAME,
cv,
whereclause,
wherargs
);
}
public long getNextQuestionID() {
//SELECT * FROM questions LEFT JOIN progress ON questions._id = progress.questionref WHERE progress._id IS NULL ORDER BY questions.number ASC
long rv = 0;
SQLiteDatabase db = this.getWritableDatabase();
String whereclause = PROGRESSTABLENAME + "." + IDCOLUMN + " IS NULL ";
String[] whereargs = null;
Cursor csr = db.query(TABLENAME +
" LEFT JOIN " + PROGRESSTABLENAME +
" ON " + TABLENAME + "." + IDCOLUMN + " = " +
PROGRESSTABLENAME + "." + QUESTIONREFCOLUMN,
null,
whereclause,
whereargs,
null,null,
TABLENAME + "." + NUMBERCOLUMN + " ASC");
if (csr.moveToFirst()) {
rv = csr.getLong(0);
}
csr.close();
return rv;
}
}
The only daunting method should be getNextQuestionID
as this uses a JOIN to combine the questions table with the progress table for determining what the next question should be.
I've commented what the query resolves to which is SELECT * FROM questions LEFT JOIN progress ON questions._id = progress.questionref WHERE progress._id IS NULL ORDER BY questions.number ASC
This saying get all columns from the questions table which is joined to the progress table column data being obtained from the progress table when the questions _id column has the same value as the questionref column of the progress table (if no match then all the progress column values will be null), hence the WHERE progress._id IS NULL (the next question is the next question that has not been answered) ORDER BY questions.number ASC makes it so that lower numbered questions appear before higher numbered questions in the resultant cursor from which we get the first row and then extract the question _id column. Note I've used a hard coded 0 for the column index (I was having issues with using the name and it's pretty late so just used 0)
You may also notice that the table create for the progress table is not in the onCreate
method, but in the createProgresstable
method this just allows it to be called independently (e.g. from the MainActivity
).
public class MainActivity extends AppCompatActivity {
DBHelper questions;
TextView mQuestion;
TextView mAnswer1;
TextView mAnswer2;
TextView mAnswer3;
TextView mAnswer4;
CheckBox mCheckBox1;
CheckBox mCheckBox2;
CheckBox mCheckBox3;
CheckBox mCheckBox4;
Button mSubmit;
long mCurrentQuestion = 0;
int mCorrectAnswer = -1;
int mCurrentAnswer = -1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mQuestion = (TextView) findViewById(R.id.question);
mAnswer1 = (TextView) findViewById(R.id.answer1_text);
mAnswer2 = (TextView) findViewById(R.id.answer2_text);
mAnswer3 = (TextView) findViewById(R.id.answer3_text);
mAnswer4 = (TextView) findViewById(R.id.answer4_text);
mCheckBox1 = (CheckBox) findViewById(R.id.answer1_checkbox);
mCheckBox2 = (CheckBox) findViewById(R.id.answer2_checkbox);
mCheckBox3 = (CheckBox) findViewById(R.id.answer3_checkbox);
mCheckBox4 = (CheckBox) findViewById(R.id.answer4_checkbox);
mSubmit = (Button) findViewById(R.id.submit);
mSubmit.setVisibility(View.INVISIBLE);
setCheckBoxListeners();
setSubmitButtonListener();
questions = new DBHelper(this); //Get Questions DBHelper
questions.createProgresstable(questions.getWritableDatabase());
if (questions.getRowCount() < 1) {
addQuestions();
}
displayCurrentQuestion();
}
@Override
protected void onResume() {
super.onResume();
mCurrentQuestion = questions.getNextQuestionID();
}
void displayCurrentQuestion() {
mQuestion.setText("Sorry no questions are ready as yet");
mAnswer1.setVisibility(View.INVISIBLE);
mAnswer2.setVisibility(View.INVISIBLE);
mAnswer3.setVisibility(View.INVISIBLE);
mAnswer4.setVisibility(View.INVISIBLE);
mCheckBox1.setVisibility(View.INVISIBLE);
mCheckBox2.setVisibility(View.INVISIBLE);
mCheckBox3.setVisibility(View.INVISIBLE);
mCheckBox4.setVisibility(View.INVISIBLE);
mSubmit.setVisibility(View.INVISIBLE);
Cursor csr = questions.getQuestionRow(mCurrentQuestion = questions.getNextQuestionID());
if (csr.moveToFirst()) {
mQuestion.setText(csr.getString(csr.getColumnIndex(DBHelper.QUESTIONCOLUMN)));
String answer1 = csr.getString(csr.getColumnIndex(DBHelper.ANSWER1COLUMN));
String answer2 = csr.getString(csr.getColumnIndex(DBHelper.ANSWER2COLUMN));
String answer3 = csr.getString(csr.getColumnIndex(DBHelper.ANSWER3COLUMN));
String answer4 = csr.getString(csr.getColumnIndex(DBHelper.ANSWER4COLUMN));
mCorrectAnswer = csr.getInt(csr.getColumnIndex(DBHelper.CORRECTCOLUMN));
if (answer1.length() > 0) {
mAnswer1.setText(answer1);
mAnswer1.setVisibility(View.VISIBLE);
mCheckBox1.setVisibility(View.VISIBLE);
}
if (answer2.length() > 0) {
mAnswer2.setText(answer2);
mAnswer2.setVisibility(View.VISIBLE);
mCheckBox2.setVisibility(View.VISIBLE);
}
if (answer3.length() > 0) {
mAnswer3.setText(answer3);
mAnswer3.setVisibility(View.VISIBLE);
mCheckBox3.setVisibility(View.VISIBLE);
}
if (answer4.length() > 0) {
mAnswer4.setText(answer4);
mAnswer4.setVisibility(View.VISIBLE);
mCheckBox4.setVisibility(View.VISIBLE);
}
}
csr.close();
}
void submitQuestion() {
String questionresult = "Incorrect.";
if (mCurrentAnswer == mCorrectAnswer) {
questionresult = " Correct.";
questions.insertProgress(mCurrentQuestion);
}
Toast.makeText(this,
"Submitted Question " +
Long.toString(mCurrentQuestion) +
" Your answer was " + questionresult
,
Toast.LENGTH_SHORT
).show();
displayCurrentQuestion();
}
void setSubmitButtonListener() {
mSubmit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
submitQuestion();
}
});
}
void setCheckBoxListeners() {
mCheckBox1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if(b) {
mCheckBox2.setChecked(false);
mCheckBox3.setChecked(false);
mCheckBox4.setChecked(false);
mSubmit.setVisibility(View.VISIBLE);
mCurrentAnswer = 1;
}
}
});
mCheckBox2.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if(b) {
mCheckBox1.setChecked(false);
mCheckBox3.setChecked(false);
mCheckBox4.setChecked(false);
mSubmit.setVisibility(View.VISIBLE);
mCurrentAnswer = 2;
}
}
});
mCheckBox3.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if(b) {
mCheckBox1.setChecked(false);
mCheckBox2.setChecked(false);
mCheckBox4.setChecked(false);
mSubmit.setVisibility(View.VISIBLE);
mCurrentAnswer = 3;
}
}
});
mCheckBox4.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if(b) {
mCheckBox1.setChecked(false);
mCheckBox2.setChecked(false);
mCheckBox3.setChecked(false);
mSubmit.setVisibility(View.VISIBLE);
mCurrentAnswer = 4;
}
}
});
}
void addQuestions() {
questions.insertQuestion("What was the name that nobody should have known?",
1,
"The Man with no Name.",
"Alan Parson Ah Ha.",
"Engelbert Humperdink.",
"Rumplestiltskin.",
4
);
questions.insertQuestion("What Band released the Album entitled Crime of the Cetury",
2,
"The Tramps",
"Super Tramp",
"Trankenstiens Feast",
"Tranvison Vamp",
2
);
questions.insertQuestion("Where is the worlds only Treacle Mine?",
3,
"Ginge",
"Ardington",
"Lockinge",
"Peasemoore",
1
);
}
}
Hopefully the above won't be to daunting, basically there's a lot of repetition.
questions.createProgresstable(questions.getWritableDatabase());
is the line where the progress table will be created, as onCreate won't be called if the database exists, note that CREATE TABLE progress IF NOT EXISTS is used so if the progress table exists it will remain.
This snippet is just for adding some questions so I test :-
if (questions.getRowCount() < 1) {
addQuestions();
}
displayCurrentQuestion();
Please feel free to ask questions if there's anything you don't understand.
Oh and this is really intended as a guide as is based on quite a few assumptions regarding naming so it will likely take a while to adapt. You may wish to start by basically copying the code and getting that working before adapting it.