Monday, May 23, 2011

Sound and frequency

One of the most pleasant aspects of the Japanese Vocabulary program I'm working on is the fact that a couple of the levels actually have audio files to go along with visuals. Fortunately, I've already implemented this in the "AnswerActivity", and just have to transfer the functionality to the Question Activity (which now includes the answer as well).

Since it's mostly static functions, or functions that ought be be static functions, and since the Question Activity class is getting kind of big, I just took all the audio play functions and stuck them into a "PlayAudioUtils" class. Then, I just move the call to play Audio from the Answer to the question activity - and done. One of the easiest changes I've ever made.

How to use frequency of use is a bit of a stickier wicket. The program randomizes the order in which the questions are asked, so what's the point of frequency? Well, the program does provide the ability to specify the range of questions in a quiz. Up till now, that meant that if you limited your quiz interval to say, 25 questions, from 1 to 25, you'd get, say, all the words beginning with A. The change we're going to implement here is to change that first set to the most frequently used 25 words, arranged at random, and the second second set the next 25 most used words, and so on. This hopefully will be a quick change.

Hmm, that's strange. It seems like it's already being read in by frequency:


public ArrayList selectByLevel(int levelIn) {


String strLevel = Integer.toString(levelIn);


Cursor cursor = this.myDataBase.query(VIEW_BY_LEVEL_FREQ, new String[] {
"level", "number", "kanji", "hiragana", "english" },
"level = ?", new String[] { strLevel }, null, null, null);

ArrayList rows = new ArrayList();

if (cursor.moveToFirst()) {
do {

int level = cursor.getInt(0);
int number = cursor.getInt(1);
String kanji = cursor.getString(2);
String hiragana = cursor.getString(3);
String english = cursor.getString(4);
if (kanji.length() == 0) {
kanji = hiragana;
}
Question row = new Question(level, number, kanji, hiragana,
english);
rows.add(row);
} while (cursor.moveToNext());
}

if (cursor != null && !cursor.isClosed()) {
cursor.close();
}

return rows;
}

This is called from initialize questions...ah, but that only stores in the word groupings now. What's driving the order of the words that go into the randomization function? What/where was that rnd function?


It's got to be something in here, in initializeQuestions:


AppState appState = (AppState) a.getApplication();

initializeQuestionsSQL(a, appState);

appState.editRangeNumbers(a);

appState.initQuizSequence(appState.quizStartNum, appState.quizEndNum);

And, here's el problemo:

public void initQuizSequence(int startNum, int endNum) {

Log.d(TAG, "initQuizSequence");

quizSequence.clear();

for (int i = startNum; i <= endNum; i++) {
quizSequence.add(new Integer(i));
}
Log.d(TAG, "exit initQuizSequence");

}


So, frequency isn't playing a role - it's base on setting up a sequence in numeric order, and using those sequential number to determine the order of the the words accessed.

With frequency, the original "id" number is no longer much good except for directly identifying and accessing a word. And since there may be gaps in the frequency number, due to being split between jlpt levels and whatnot, the order should be driven by the level freq view. So, it's going to have to have a way of getting to the nth record through the nth + m record. The best solution may be a query with ? parameters.

Let's add that to the DataBaseHelper.

No, actually, we've got to run sequentially through all the available rows until we get to the number of records requested.

Let's try something like this:

public void initQuizSequence(int startNum, int endNum) {

Log.d(TAG, "initQuizSequence");

quizSequence.clear();

DataBaseHelper dbHelper = new DataBaseHelper(this);

ArrayList rows = dbHelper.selectByLevel(jlptLevel);

int cntr = 0;

for (Question question : rows){

cntr++;

if ((cntr >= startNum) || (cntr <= endNum)) {

// question.number is like an id
quizSequence.add(new Integer(question.number));
}

if (cntr > endNum){
break; // no need to go further
}
}
Log.d(TAG, "exit initQuizSequence");

Ok, after an unnecessary amount of debugging because I didn't copy the database access from someplace else, I have now run into a crash on a null pointer on "omou"..

Plus, my carefully worked out scheme for highlighting the correct answer seem to also be randomly highlighting some other answers.

One thing at a time. I think I will turn off the shuffle for now. And then see where it crashes.

Ok, it crashed on npe just after "hodo". A dump of the database show it has a number, so the db is not the problem. That's the return rows, and it shows nothing was added to rows - the selection criteria wasn't met.

Ok, the number of rows returned is zero. Why? Ok, it's getting it from the quiz sequence index, which is from start number to end number.

Then end number - is 10. Ahh.

The problem is I can have this situation:

Start number = 25
End number = 50

So, then I have to calculate the difference between those two; and compare that with number questions asked.

If it's greater, then I show them the score page and do something from there.

Otherwise, I also have to check if the end number exceeds the nag number; and if so, display a nag message or something.


Ok, here's the logic now:

if ((appState.quizEndNum - appState.quizStartNum) <= appState.numQuestionsAsked) {

Context context = getApplicationContext();
int duration = Toast.LENGTH_LONG;
CharSequence text = "Quiz Complete; restarting";
appState.quizSequenceIndex = appState.quizStartNum;

Toast toast = Toast.makeText(context, text, duration);
toast.show();

InitUtils.clearQuiz(this);
finish();

} else {

incrementQuestion();

}

It's till crashing; I think it must have something to do with clearing the quiz, i.e. the quiz sequence, and not re-initializing it. I tried tossing in a finish, to take me back to the initial activity. I think it makes sense, but I'm getting some message like finish already executed.

Well, I don't need to re-initialize the word array, but I do need to reinitialize the sequence. Let's see if that's called from anywhere it needs to to be called from - like the start quiz button.

Ok, the first thing I'm going to try is moving the initialize activity to the start quiz button. This will set me up for returning to this display when the quiz is complete and having everything handled from there.

That seems to work ok. Now, let's figure out why it's not getting back there.

Ok, I deleted the clear quiz logic; that should now be handled by the start quiz button. I still don't get why I'm not seeing the toast message; maybe it crashes too soon. Let's try it again.

Yes, that did it. It's now displaying the toast message, "quiz complete", and returning to the start activity. There the customer can change the settings or go right back to the same quiz. Awesome. That's a wrap.

No comments:

Post a Comment