I would like to ask for some help with my android code. I am trying to develop a quiz app using SQLite.Number of possible answers differs so i need to hide radio buttons from the main screen if answers e.g. are 3 and not 4 (4 is by default the number of the radio buttons). Tried to use:
if (DataContract.QuestionTable.COLUMN_ANSWER4.isEmpty ()){ radioButton4.setVisibility (View.INVISIBLE); }
but does not seem to work.I'm new in android programming and this is my first project so every comment will be very helpful. Thank you.
Here's a demo with a suggested technique, considering the limited amount of code posted with the question.
This utilises two tables to conform with a normalised approach. A table for the questions and a table for answers. Each answer (the Children) has a link/map/relationship/association with a single Question (the Parent). To prevent referential integrity issues a Foreign Key constraint has been used.
First a few POJO's for the Questions, the Answers and QuestionWithAnswers (i.e. it's answers)
QuestionPOJO
class QuestionPOJO {
long questionId;
String questionText;
public QuestionPOJO(long questionId, String questionText) {
this.questionId = questionId;
this.questionText = questionText;
}
public long getQuestionId() {
return questionId;
}
public void setQuestionId(long questionId) {
this.questionId = questionId;
}
public String getQuestionText() {
return questionText;
}
public void setQuestionText(String questionText) {
this.questionText = questionText;
}
}
AnswerPOJO
class AnswerPOJO {
long answerId;
long questionMap;
String answerText;
boolean correct = false;
public AnswerPOJO(long answerid, long questionMap, String answerText, boolean correct) {
this.answerId = answerid;
this.questionMap = questionMap;
this.answerText = answerText;
this.correct = correct;
}
public long getAnswerId() {
return answerId;
}
public void setAnswerId(long answerId) {
this.answerId = answerId;
}
public long getQuestionMap() {
return questionMap;
}
public void setQuestionMap(long questionMap) {
this.questionMap = questionMap;
}
public boolean isCorrect() {
return correct;
}
public void setCorrect(boolean correct) {
this.correct = correct;
}
public String getAnswerText() {
return answerText;
}
public void setAnswerText(String answerText) {
this.answerText = answerText;
}
}
and QuestionWithAnswerPOJO
class QuestionWithAnswersPOJO {
QuestionPOJO question;
ArrayList<AnswerPOJO> answers = new ArrayList<>();
public QuestionWithAnswersPOJO(QuestionPOJO question, List<AnswerPOJO> answers) {
this.question = question;
this.answers.clear();
this.answers.addAll(answers);
}
public QuestionPOJO getQuestion() {
return question;
}
public void setQuestion(QuestionPOJO question) {
this.question = question;
}
public ArrayList<AnswerPOJO> getAnswers() {
return answers;
}
public void setAnswers(ArrayList<AnswerPOJO> answers) {
this.answers = answers;
}
}
Now the DatabaseHelper, that handles all the database activity. Including methods to add and get Questions and the Answers and notably to get the Answers that belong to a question.
class DatabaseHelper extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "questions.db";
public static final int DATABASE_VERSION = 1;
public static final String QUESTION_TABLE = "question";
public static final String QUESTION_ID_COLUMN = BaseColumns._ID;
public static final String QUESTION_TEXT_COLUMN = "question_text";
public static final String ANSWER_TABLE = "answer";
public static final String ANSWER_ID_COLUMN = BaseColumns._ID;
public static final String ANSWER_TEXT_COLUMN = "answer_text";
public static final String ANSWER_QUESTION_MAP_COLUMN = "question_map";
public static final String ANSWER_CORRECT_COLUMN = "correct";
private static volatile DatabaseHelper instance = null;
private DatabaseHelper(Context context) {
super(context,DATABASE_NAME,null,DATABASE_VERSION);
}
private static SQLiteDatabase db = null;
public static DatabaseHelper getInstance(Context context, boolean forceOpen) {
if (instance == null) {
instance = new DatabaseHelper(context);
}
if (forceOpen) {
db = instance.getWritableDatabase();
}
return instance;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE IF NOT EXISTS " + QUESTION_TABLE + "(" +
QUESTION_ID_COLUMN + " INTEGER PRIMARY KEY," +
QUESTION_TEXT_COLUMN + " TEXT" +
");");
db.execSQL("CREATE TABLE IF NOT EXISTS " + ANSWER_TABLE + "(" +
ANSWER_ID_COLUMN + " INTEGER PRIMARY KEY," +
ANSWER_TEXT_COLUMN + " TEXT," +
ANSWER_QUESTION_MAP_COLUMN + " INTEGER REFERENCES " + QUESTION_TABLE + "(" + QUESTION_ID_COLUMN + ") ON DELETE CASCADE ON UPDATE CASCADE," +
ANSWER_CORRECT_COLUMN + " INTEGER DEFAULT 0 /* false */" +
");");
}
@Override
public void onUpgrade(SQLiteDatabase db, int i, int i1) {
}
// Fully comprehensive Question insert
public long insertQuestion(Long questionId, String questionText) {
init_db_AsWriteableDatabase();
long rv = -2;
ContentValues cv = new ContentValues();
if (questionId != null && questionId > 0) {
cv.put(QUESTION_ID_COLUMN,questionId);
}
if (questionText != null && questionText.length() > 0) {
cv.put(QUESTION_TEXT_COLUMN,questionText);
}
if (cv.size() > 0) {
rv = db.insert(QUESTION_TABLE,null,cv);
}
return rv;
}
// Concise Question insert
public long insertQuestion(String questionText) {
return insertQuestion(null,questionText);
}
// Fully comprehensive Answer insert
public long insertAnswer(Long answerId, long questionMap, String answerText, boolean correct) {
init_db_AsWriteableDatabase();
long rv = -2;
ContentValues cv = new ContentValues();
if (answerId != null && answerId > 0) {
cv.put(ANSWER_ID_COLUMN,answerId);
}
if (answerText != null && answerText.length() > 0) {
cv.put(ANSWER_CORRECT_COLUMN,correct);
cv.put(ANSWER_TEXT_COLUMN,answerText);
cv.put(ANSWER_QUESTION_MAP_COLUMN,questionMap);
rv = db.insert(ANSWER_TABLE,null,cv);
}
return rv;
}
// long concise Answer insert
public long insertAnswer(long questionMap, String answerText, boolean correct) {
return insertAnswer(null,questionMap,answerText,correct);
}
public long insertAnswer(long questionMap, String answerText) {
return insertAnswer(questionMap,answerText,false);
}
// short concise Answer insert
private void init_db_AsWriteableDatabase() {
if (db == null) {
db = this.getWritableDatabase();
}
}
@SuppressLint("Range")
public QuestionPOJO getQuestionById(long questionId) {
QuestionPOJO rv = null;
init_db_AsWriteableDatabase();
Cursor csr = db.query(QUESTION_TABLE,null,QUESTION_ID_COLUMN+"=?",new String[]{String.valueOf(questionId)},null,null,null);
if (csr.moveToNext()) {
rv = new QuestionPOJO(csr.getLong(csr.getColumnIndex(QUESTION_ID_COLUMN)),csr.getString(csr.getColumnIndex(QUESTION_TEXT_COLUMN)));
}
csr.close();
return rv;
}
@SuppressLint("Range")
public List<AnswerPOJO> getAnswersForQuestion(long questionId, boolean onlyCorrect) {
init_db_AsWriteableDatabase();
ArrayList<AnswerPOJO> rv = new ArrayList<>();
StringBuilder whereClause = new StringBuilder();
whereClause.append(ANSWER_QUESTION_MAP_COLUMN + "=?");
if (onlyCorrect) {
whereClause.append(" AND ").append(ANSWER_CORRECT_COLUMN);
}
Cursor csr = db.query(ANSWER_TABLE,null,whereClause.toString(),new String[]{String.valueOf(questionId)},null,null,null);
while (csr.moveToNext()) {
rv.add(
new AnswerPOJO(
csr.getLong(csr.getColumnIndex(ANSWER_ID_COLUMN)),
questionId,
csr.getString(csr.getColumnIndex(ANSWER_TEXT_COLUMN)),
csr.getInt(csr.getColumnIndex(ANSWER_CORRECT_COLUMN)) > 0
)
);
}
csr.close();
return rv;
}
}
Finally to put it all together and activity that has a layout for 4 radio buttons along with the associated answer as a TextView.
So the layout is:-
<?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=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!">
</TextView>
<RadioGroup
android:id="@+id/question_radiogroup"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RadioButton
android:id="@+id/answer1_radioButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:ignore="DuplicateSpeakableTextCheck"></RadioButton>
<TextView
android:id="@+id/answer1_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>
<RadioButton
android:id="@+id/answer2_radioButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</RadioButton>
<TextView
android:id="@+id/answer2_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>
<RadioButton
android:id="@+id/answer3_radioButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</RadioButton>
<TextView
android:id="@+id/answer3_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>
<RadioButton
android:id="@+id/answer4_radioButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</RadioButton>
<TextView
android:id="@+id/answer4_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>
</RadioGroup>
</LinearLayout>
And the activity to demonstrate:-
public class MainActivity extends AppCompatActivity {
DatabaseHelper dbHelper;
RadioButton[] radiobuttons = new RadioButton[4];
TextView[] answerTexts = new TextView[4];
QuestionWithAnswersPOJO currentQuestionWithAnswers;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*
prepare Radion Buttons and associated TextViews
*/
radiobuttons[0] = this.findViewById(R.id.answer1_radioButton);
radiobuttons[1] = this.findViewById(R.id.answer2_radioButton);
radiobuttons[2] = this.findViewById(R.id.answer3_radioButton);
radiobuttons[3] = this.findViewById(R.id.answer4_radioButton);
answerTexts[0] = this.findViewById(R.id.answer1_textview);
answerTexts[1] = this.findViewById(R.id.answer2_textview);
answerTexts[2] = this.findViewById(R.id.answer3_textview);
answerTexts[3] = this.findViewById(R.id.answer4_textview);
/*
Prepare to use Database
*/
dbHelper = DatabaseHelper.getInstance(this,true);
SQLiteDatabase db = dbHelper.getWritableDatabase();
/* Clear any existing data for consistent results */
db.delete(DatabaseHelper.ANSWER_TABLE,null,null);
db.delete(DatabaseHelper.QUESTION_TABLE,null,null);
/* Add some demo data 1 question with 5 answers (comment out to reduce number of answers)*/
long q1id = dbHelper.insertQuestion("What is 1 + 1");
dbHelper.insertAnswer(q1id,"It is 1");
dbHelper.insertAnswer(q1id,"it is 2", true);
dbHelper.insertAnswer(q1id,"It is 3");
dbHelper.insertAnswer(q1id,"It is 4");
dbHelper.insertAnswer(q1id,"It is something Else"); // will be ignored because only 4 radio buttons
/* Get the question with the answers, however many ot has */
currentQuestionWithAnswers = new QuestionWithAnswersPOJO(dbHelper.getQuestionById(q1id),dbHelper.getAnswersForQuestion(q1id,false));
/* setup (refresh) the radio buttons and textviews */
getAndSetRadioButtons(currentQuestionWithAnswers);
}
/*
Does as it says
*/
private void getAndSetRadioButtons(QuestionWithAnswersPOJO qwa) {
// Clear All
for (int i=0;i < radiobuttons.length; i++) {
radiobuttons[i].setVisibility(View.GONE);
answerTexts[i].setText("");
answerTexts[i].setVisibility(View.GONE);
}
/* show only the least of answers/radio buttons */
int numberToShow = radiobuttons.length;
if (qwa.answers.size() < radiobuttons.length) {
numberToShow = qwa.answers.size();
}
int i = 0;
for(AnswerPOJO a: qwa.answers) {
if (i < numberToShow) {
radiobuttons[i].setVisibility(View.VISIBLE);
answerTexts[i].setVisibility(View.VISIBLE);
answerTexts[i++].setText(a.answerText);
} else {
/* nothing more to do so early break out of the loop */
break;
}
}
}
}
Results
Result 1 - run with the 5 answers (see comments re 5th answer)
Result 2 - All bar 1 answer comment out so the question has just the 1 answer
The code used:-
long q1id = dbHelper.insertQuestion("What is 1 + 1");
dbHelper.insertAnswer(q1id,"It is 1");
//dbHelper.insertAnswer(q1id,"it is 2", true);
//dbHelper.insertAnswer(q1id,"It is 3");
//dbHelper.insertAnswer(q1id,"It is 4");
//dbHelper.insertAnswer(q1id,"It is something Else"); // will be ignored because only 4 radio buttons
The display :-
Result 3 - first and 5th answers only inserted
and so on.
Additional after code has been posted.
Additional Answer as code has now been added.
You say:-
Tried to use:
if (DataContract.QuestionTable.COLUMN_ANSWER4.isEmpty ()){ radioButton4.setVisibility (View.INVISIBLE); }
but does not seem to work.
If DataContract.QuestionTable.COLUMN_ANSWER4 were empty then would be facing more serious issues as it is the column name.
You should be checking for the contents of the column which has been retrieved from DB and placed into currentQuestion, for the question being inspected.
I believe that using (old code commented out):-
radioButton1.setText(currentQuestion.getAnswer1 ());
radioButton2.setText(currentQuestion.getAnswer2 ());
radioButton3.setText(currentQuestion.getAnswer3 ());
radioButton4.setText(currentQuestion.getAnswer4 ());
if(currentQuestion.getAnswer4() == null || currentQuestion.getAnswer4().isEmpty()) {
radioButton4.setVisibility(View.INVISIBLE);
} else {
radioButton4.setVisibility(View.VISIBLE); // just in case it is INVISIBLE
radioButton4.setText(currentQuestion.getAnswer4());
}
/*
if (DataContract.QuestionTable.COLUMN_ANSWER4.isEmpty ()){
radioButton4.setVisibility (View.INVISIBLE);
} else {
radioButton4.setText(currentQuestion.getAnswer4 ());
}
*/
Will resolve this issue. e.g. at Q3:-