Complete Solution 3 with Explanations


#1

I wound up re-writing the solution parts 1&2 after doing 3. I simply found that the solution to #3 would solve #1 and #2 so I didn’t want all the duplicate ways of handling the scenarios. Below is the complete solution which includes the saving of states and intents.

QuizActivity.java

I first created a set whose purpose is to hold all of the question indices where a cheat event occurred. Why a set and not an array? Given users can actually cheat multiple times on the same question I did not want to continually add the same index to the array. While this wouldn’t cause an issue with the functioning of the program, I didn’t think it the best way to handle. A set will ensure that the values added are unique rather than a conditional each time to see if the index was a repeat before adding.

Below is the method that checks the user’s answer. In order to produce the correct response I first check if the question index is in the cheat set. If it is they cheated and the appropriate message is displayed.

[code]private void checkAnswer(boolean userPressedTrue)
{
boolean answerIsTrue = mQuestionBank[mCurrentIndex].isTrueQuestion();

    int messageResId = 0;

    if (mCheat_index.contains(mCurrentIndex))
        messageResId = R.string.judgement_toast;
    else
    {
        if (userPressedTrue == answerIsTrue)
            messageResId = R.string.correct_toast;
        else
            messageResId = R.string.incorrect_toast;
    }

    Toast.makeText(this,messageResId, Toast.LENGTH_SHORT).show();
}[/code]

This is the method called when we return FROM the cheat activity. In it all I want is the set of cheating indices. The book asked us to write the conditional with this structure. Personally I would have gone with data != null rather than the return.

protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (data == null) return; mCheat_index = (Set) data.getSerializableExtra(CheatActivity.EXTRA_CHEAT_LOG); }

Here are the relevant statements from the method for purposes of restoring the state should the user rotate the device. Additionally the method used when the user elects to press the cheat button. Here I send the cheat activity the question’s answer, the cheat set, and the current question’s index.

[code]protected void onCreate(Bundle savedInstanceState)
{

if (savedInstanceState != null)
{
mCurrentIndex = savedInstanceState.getInt(KEY_INDEX, 0);
mCheat_index = (Set) savedInstanceState.getSerializable(KEY_CHEAT);
}

    mCheatButton.setOnClickListener(new View.OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
            Intent i = new Intent(QuizActivity.this,CheatActivity.class);
            boolean answerIsTrue = mQuestionBank[mCurrentIndex].isTrueQuestion();
            i.putExtra(CheatActivity.EXTRA_ANSWER_IS_TRUE,answerIsTrue);
            i.putExtra(CheatActivity.EXTRA_CHEAT_LOG, (java.io.Serializable) mCheat_index);
            i.putExtra(CheatActivity.EXTRA_QUESTION_INDEX,mCurrentIndex);
            startActivityForResult(i, 0);
        }

     ....

}[/code]

The method used when the user rotates or otherwise destroys the current activity. This saves the relevant data which includes the index of the current question and the cheat set.

public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); Log.i(TAG, "onSaveInstanceState"); savedInstanceState.putInt(KEY_INDEX, mCurrentIndex); savedInstanceState.putSerializable(KEY_CHEAT, (java.io.Serializable) mCheat_index); }

CheatActivity.java

The references necessary to handle both the data going between the two activities as well as to save if the user destroys the current activity (note, I am not using the book’s reverse domain)

public static final String EXTRA_ANSWER_IS_TRUE = "com.example.firefox.geoquiz.answer_is_true";
public static final String EXTRA_QUESTION_INDEX = "com.example.firefox.geoquiz.question_index";
public static final String EXTRA_CHEAT_LOG = "com.example.firefox.geoquiz.cheat_index";
public static final String KEY_QUESTION_INDEX = "cheat";
public static final String KEY_CHEAT_INDEX = "cheat_index";

The two local variables needed to hold the question’s index and the cheat set.

private int mQuestion_index;
private Set mCheat_index;

After a cheat is displayed, this method is executed. It sets what we will send back to the quiz activity which in this case is only the cheat index.

private void setAnswerShownResult()
    {
        Intent data = new Intent();
        data.putExtra(EXTRA_CHEAT_LOG, (java.io.Serializable) mCheat_index);
        setResult(RESULT_OK, data);
    }

Here we will get the data that the quiz activity sent to us. We will also handle restoring the information should the user destroy the activity by say rotating the device. Lastly, we will handle the user going forward with the cheat by adding the question index to the cheat set and updating the extra for the intent by calling the appropriate method.

protected void onCreate(Bundle savedInstanceState)
{
  ....
   mAnswerIsTrue = getIntent().getBooleanExtra(EXTRA_ANSWER_IS_TRUE, false); 
   mCheat_index = (Set) getIntent().getSerializableExtra(EXTRA_CHEAT_LOG);
   mQuestion_index = getIntent().getIntExtra(EXTRA_QUESTION_INDEX,0);
   setAnswerShownResult();

   if (savedInstanceState != null)
   {
       mCheat_index = (Set) savedInstanceState.getSerializable(KEY_CHEAT_INDEX);
       mQuestion_index = savedInstanceState.getInt(KEY_QUESTION_INDEX);  
   }

   mShowAnswer.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                if (mAnswerIsTrue)
                    mAnswerTextView.setText(R.string.true_button);
                else
                    mAnswerTextView.setText(R.string.false_button);
                mCheat_index.add(mQuestion_index);
                setAnswerShownResult();
            }

        });

}