All challenges my solution


#1

The challenges for chapter 5 were some of the hardest so far for me, probably because I have a small amount of Java under my belt to begin with. This took me hours to complete the challenges and get the program working how I wanted it to. I’m sure that at least some of my code lacks elegance but maybe this will help someone out there.
QuizActivity.java

[code]package com.bignerdranch.com.geoquiz;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;

public class QuizActivity extends ActionBarActivity {

// Variables
private static final String TAG = "QuizActivity";
// variable name string for the savedInstantState question currently in use 
private static final String KEY_INDEX = "index";
// variable name string for the savedInstantState status of whether the player cheated or not
private static final String KEY_CHEATER = "cheater";
// variable name string for the savedInstantState status of whether each question was cheated on or not
private static final String KEY_CHEAT_ARRAY = "cheatarray";

private Button mTrueButton;
private Button mFalseButton;
private Button mCheatButton;
private ImageButton mNextButton;
private ImageButton mPrevButton;
private TextView mQuestionTextView;
private TrueFalse[] mQuestionBank = new TrueFalse[] {
		new TrueFalse(R.string.question_oceans, true),
		new TrueFalse(R.string.question_mideast, false),
		new TrueFalse(R.string.question_africa, false),
		new TrueFalse(R.string.question_americas, true),
		new TrueFalse(R.string.question_asia, true),
};
// int array to hold the status of whether or not each question was cheated on 1=no cheat, 2=cheated
private int[] mCheatBank = {1, 1, 1, 1, 1};
private int mCurrentIndex = 0;
private boolean mIsCheater;
private void updateQuestion() {
	//Log.d(TAG, "Updating question text for question #" + mCurrentIndex, new Exception());
	int question = mQuestionBank[mCurrentIndex].getQuestion();
	mQuestionTextView.setText(question);
}
private void checkAnswer(boolean userPressedTrue) {
	boolean answerIsTrue = mQuestionBank[mCurrentIndex].isTrueQuestion();
	int messageResId = 0;
	
	if (userPressedTrue == answerIsTrue) {
		if (mCheatBank[mCurrentIndex] == 2) {// if the index # of the current question is set in the question cheat int array
			messageResId = R.string.judgment_toast;// display a chastisement
		} else {// if it's not then display regular message
			messageResId = R.string.correct_toast;    
		}			
	} else {
		if (mCheatBank[mCurrentIndex] == 2) {
			messageResId = R.string.judgment_toast;
		} else {
			messageResId = R.string.incorrect_toast;
		}			
	}
	Toast.makeText(this, messageResId, Toast.LENGTH_SHORT).show();
}


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.d(TAG, "onCreate(Bundle) called for GeoQuiz");
    setContentView(R.layout.activity_quiz);
    mQuestionTextView = (TextView)findViewById(R.id.question_text_view);
    mTrueButton = (Button)findViewById(R.id.true_button);
    mTrueButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
        	checkAnswer(true);
        }
    });
    mFalseButton = (Button)findViewById(R.id.false_button);
    mFalseButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
        	checkAnswer(false);
        }
    });
    mNextButton = (ImageButton)findViewById(R.id.next_button);
    mNextButton.setOnClickListener(new View.OnClickListener() {
		
		@Override
		public void onClick(View arg0) {
			// TODO Auto-generated method stub
			mCurrentIndex = (mCurrentIndex + 1) % mQuestionBank.length;
			updateQuestion();
		}
	});
    updateQuestion();
    
    mPrevButton = (ImageButton)findViewById(R.id.prev_button);
    mPrevButton.setOnClickListener(new View.OnClickListener() {
		
		@Override
		public void onClick(View arg0) {
			// TODO Auto-generated method stub
			mCurrentIndex = (mCurrentIndex - 1) % mQuestionBank.length;
			updateQuestion();
		}
	});
    updateQuestion();
    
    mQuestionTextView = (TextView)findViewById(R.id.question_text_view);
    mQuestionTextView.setOnClickListener(new View.OnClickListener() {
		
		@Override
		public void onClick(View arg0) {
			mCurrentIndex = (mCurrentIndex + 1) % mQuestionBank.length;
			updateQuestion();
			
		}
	});
    if (savedInstanceState != null) {// if the instance state was saved
    	mCurrentIndex = savedInstanceState.getInt(KEY_INDEX, 0);// the current question index # pulled from that saved state
    	mIsCheater = savedInstanceState.getBoolean(KEY_CHEATER, false);// the current status of whether the user cheated on this ? is pulled
    	mCheatBank = savedInstanceState.getIntArray(KEY_CHEAT_ARRAY);// the current status of the int array that holds cheat/not for each ? pulled
    }
    mCheatButton = (Button)findViewById(R.id.cheat_button);
    mCheatButton.setOnClickListener(new View.OnClickListener() {
		
		@Override
		public void onClick(View arg0) {
			// start cheat activity
			Intent i = new Intent(QuizActivity.this, CheatActivity.class);
			boolean answerIsTrue = mQuestionBank[mCurrentIndex].isTrueQuestion();
			i.putExtra(CheatActivity.EXTRA_ANSWER_IS_TRUE, answerIsTrue);
			startActivityForResult(i, 0);
			
		}
	});
    updateQuestion();
    
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	if (data == null) {
		return;
	}
	// pull the cheat status reported back by CheatActivity
	mIsCheater = data.getBooleanExtra(CheatActivity.EXTRA_ANSWER_SHOWN, false);
	if (mIsCheater) {// if they did cheat
		mCheatBank[mCurrentIndex] = 2;// set the current ?'s cheat status to cheated on in the array(2)
	}
}

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
	super.onSaveInstanceState(savedInstanceState);
	Log.i(TAG, "onSaveInstanceState");
	savedInstanceState.putInt(KEY_INDEX, mCurrentIndex);// save the index # of the current ? onSaveInstanceState issuance
	savedInstanceState.putBoolean(KEY_CHEATER, mIsCheater);// save the cheater status of the user onSaveInstanceState issuance
	savedInstanceState.putIntArray(KEY_CHEAT_ARRAY, mCheatBank);// save the cheat status of all ?'s onSaveInstanceState issuance
}

@Override
public void onStart() {
    super.onStart();
    Log.d(TAG, "onStart() called for GeoQuiz");
}

@Override
public void onPause() {
    super.onPause();
    Log.d(TAG, "onPause() called for GeoQuiz");
}

@Override
public void onResume() {
    super.onResume();
    Log.d(TAG, "onResume() called for GeoQuiz");
}

@Override
public void onStop() {
    super.onStop();
    Log.d(TAG, "onStop() called for GeoQuiz");
}

@Override
public void onDestroy() {
    super.onDestroy();
    Log.d(TAG, "onDestroy() called for GeoQuiz");
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.quiz, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();
    if (id == R.id.action_settings) {
        return true;
    }
    return super.onOptionsItemSelected(item);
}

}
[/code]

CheatActivity.java

[code]package com.bignerdranch.com.geoquiz;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class CheatActivity extends Activity {

//variables

// variable name string for whether the answer to the question is true or false
public static final String EXTRA_ANSWER_IS_TRUE = "com.bignerdranch.android.geoquiz.answer_is_true";
// variable name string for the status of having shown the answer on savedInstantState issuance 
public static final String EXTRA_ANSWER_SHOWN = "com.bignerdranch.android.geoquiz.answer_shown";
// variable name string for the status of whether the user cheated
public static final String KEY_CHEATER = "cheater";

private boolean mAnswerIsTrue;
private TextView mAnswerTextView;
private Button mShowAnswer;
private Boolean mIsCheater;

private void setAnswerShownResult(boolean isAnswerShown) {
	Intent data = new Intent();
	data.putExtra(EXTRA_ANSWER_SHOWN, isAnswerShown);
	setResult(RESULT_OK, data);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.activity_cheat);
	
	if (savedInstanceState != null) {// if there was a savedInstanceState issuance
		setAnswerShownResult(savedInstanceState.getBoolean(KEY_CHEATER, false));// was the answer displayed before savedInstanceState if so forward that on
		mIsCheater = savedInstanceState.getBoolean(KEY_CHEATER);// did the user cheat before savedInstanceState
		mAnswerIsTrue = savedInstanceState.getBoolean(EXTRA_ANSWER_IS_TRUE, false);// was the answer to the ? cheated on true
		mAnswerTextView = (TextView)findViewById(R.id.answerTextView);
		if ((mAnswerIsTrue == true) && (mIsCheater == true)) {// if the answer was true, and it was viewed(cheated)
			mAnswerTextView.setText(R.string.true_button);// then display it again
		} else if ((mAnswerIsTrue == false) && (mIsCheater == true)) {//if the answer was false, and it was viewed(cheated)
			mAnswerTextView.setText(R.string.false_button);// display it again
		}
		
    } else {// no savedInstanceState
    	mIsCheater = false;// they haven't cheated yet
    	setAnswerShownResult(false);// they haven't seen the answer yet
    }
	
	
	mAnswerIsTrue = getIntent().getBooleanExtra(EXTRA_ANSWER_IS_TRUE, false);
	mAnswerTextView = (TextView)findViewById(R.id.answerTextView);
	mShowAnswer = (Button)findViewById(R.id.showAnswerButton);
	mShowAnswer.setOnClickListener(new View.OnClickListener() {
		
		@Override
		public void onClick(View arg0) {
			
			if (mAnswerIsTrue) {
				mAnswerTextView.setText(R.string.true_button);
			} else {
				mAnswerTextView.setText(R.string.false_button);
			}
			setAnswerShownResult(true);// the answer was seen
			mIsCheater = true;// the user cheated
		}
	});
}

 @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
    	super.onSaveInstanceState(savedInstanceState);
    	savedInstanceState.putBoolean(KEY_CHEATER, mIsCheater);// save the cheat status of the user onSaveInstanceState issuance
    	savedInstanceState.putBoolean(EXTRA_ANSWER_IS_TRUE, mAnswerIsTrue);// get whether ? was True/false onSaveInstanceState issuance
    }

}
[/code]


#2

Thanks for your code. Was very helpful to me.

One thing I find is that the “incorrect_judgement_toast” doesn’t get used in the code. I’m going to play with that when I get a little more time.

Thanks again.


#3

Looks like all that was needed was “incorrect_judgement” on false rather than “judgement”…

[quote] private void checkAnswer(boolean userPressedTrue)

else
{
if (mCheatBank[mCurrentIndex] == 2)
{
messageResId = R.string.incorrect_judgement_toast;
}
else
{
messageResId = R.string.incorrect_toast;
}[/quote]


#4

My solution was to add a “hasCheated” boolean variable to the TrueFalse class. When the TrueFalse object is instantiated it is false. The variable is set to true for a particular TrueFalse object when the person has cheated. Once set to true it can never be set to false. I did that by setting it using an ‘or’, e.g hasCheated = hasCheated || justCheated.


#5

Thank you very much . Your solution is help me so much . :smiley:


#6

@ BigDaddyCF…

Your solution for ensuring the user cannot cycle through the questions in order to reset the cheat status is quite nice. One change I would make is to initialize the array in a loop rather than initializing it when you declare the array. That way you don’t have to do any additional work when you want to add more questions.

Rather than:

private int[] mCheatBank = {1, 1, 1, 1, 1};

do this:

private int[] mCheatBank = new int[mQuestionBank.length];

This creates an array that is the same size as your questionbank.

Then create a method to initialize the array:

private int[] initializeCheatBank(){
        for(int i = 0; i < mCheatBank.length; i++){
            mCheatBank[i] = 0;
        }
        return mCheatBank;
    }

Finally, call initializeCheatBank(); in the onCreate() method.


#7

There is bug , at the launch of the app if you press the prev button the app crashes with a ArrayIndexOutOfBound exception ,
Solution is to add an if block , as shown below.

            mPrevButton = (Button) findViewById(R.id.prev_button);
	mPrevButton.setOnClickListener(new View.OnClickListener() {
		
		@Override
		public void onClick(View v) {
			int question;
			mCurrentIndex =(mCurrentIndex-1) % 	mQuestionBank.length;
			if(mCurrentIndex >= 0){
			question = mQuestionBank[mCurrentIndex].getQuestion();
			mQuestionTextView.setText(question);
			mIsCheater = false;
			updateQuestion();}
			else{
				mCurrentIndex = 0;
				question = mQuestionBank[mCurrentIndex].getQuestion();
				mQuestionTextView.setText(question);
				mIsCheater = false;
				updateQuestion();
				
			}
			
			
		}
	});

#8

Instead of creating another array for the boolean values to monitor cheating you could add a third parameter to your truefalse objects. Then add the getter and setter methods to work with the new boolean.