teaching machines

CS 491 Assignment 1 – Post mortem

September 30, 2011 by . Filed under cs491 mobile, fall 2011, postmortems.

So, the flashcard app – a simple idea that, in some areas, proved to be fairly challenging. My flashcard app generates random math problems. The user can customize the range of the randomly generated numbers along with which math operations are used, and how many total problems are in the set. The UI is fairly simple – EditViews for editing numbers and Checkboxes for including operations. The app contains 3 separate Activities. The first Activity is the setup screen. I did not set this up to persist data across Activity rebuilds. My rationale for this was that there aren’t many options, so there’s really no need. Though, Android does a decent job of rebuilding the Activity automatically on my phone. The second Activity is the actual flashcard. This includes the number of times a problem has been attempted, a timer showing how long the user has been on the current problem, and a button to check the answer.

 

The main flashcard Activity is setup to save state when the Activity needs to be destroyed and recreated. This is done by saving everything to the defaultSystemPreferences. I wrote a Utility to wrap the SystemPreferences to I didn’t have to deal with the whole prefs.edit().putX().commit() structure. With the utility you can just say prefs.putX(). Not a big thing, but a little time saver. Particularly interesting in this Activity is the Handler. There is a single Handler that is responsible for incrementing the timer and dismissing the feedback dialog (the dialog with the image indication Correct or Incorrect). I’ve included the initialization code for the Handler:

 

timerThread = new Runnable() {

@Override

public void run() {

//this is a message to increment the timer

timer += 1000;

timerView.setText(timeFormatter.format(new Date(timer)));

startTimer();

}

};

messageHandler = new Handler(){

@Override

publicvoid handleMessage(Message msg){

if(msg.what == 0){

//this is a message to dismiss the AlertDialog

dismissFeedbackDialog();

//display the next question

if(isSubmittedAnswerCorrect){

if(!isLastQuestion()){

displayNewQuestion();

}else{

//end the round

Intent intent = new Intent(FlashCardActivity.this,

SummaryActivity.class);

FlashCardActivity.this.startActivity(intent);

}

}

//start the timer going again

startTimer();

}

}

};

 

The Runnable is responsible for incrementing the time. This couldn’t be done with a Message because messages can’t be cancelled while Runnables can be. The Runnable needs to be cancelled so that the timer stops when the feedback dialog is up. The Runnable is posted to the Handler in the startTimer() method. This can bee seen in the above code snippet in the handleMessage() method. After a new question is displayed, the timer is started.

 

You can also see in above snippet the starting of a new Intent when all the questions are answered. This third Activity is simply a summary of all the question. It lists all the information the user had selected for the round along with the total time spent on the problem set. Then there is a list of all the problems. Creating this list proved an interesting problem. Somehow I needed to pass a bunch of information to the SummaryActivity from the FlashCardActivity. Intent has a method to add data, but this data can only be Strings. While I could have accomplished what I needed with Strings, it didn’t seems like a very elegant solution.

 

What I did instead was create a Singleton data structure. This is the QuestionTracker class. Record objects can be statically added to this class in the following way:

 

QuestionTracker.addRecord(new Record());

 

Records are added after the user successfully answers a question. It is simply a summary of all the data relating a the given problems.

 

The SummaryActivity then pulls in all of these Records by calling:

 

QuestionTracker.getRecords();

 

Using the Singleton Pattern, data didn’t need to be explicitly passed to the SummaryActivity, instead it was posted and pulled from the QuestionTracker singleton. I should not though, that I have no idea how stable this model is. For instance, the data stored in the singleton might be lost when the device is restarted.

 

The SummaryActivity also persists data across Activity re-creation. This was done unintentionally, but because the SummaryActivity at no point changes the data on the screen, everything is loaded fresh, but identically every time the Activity is recreated (for a given problem set).

 

Another interesting thing in SummaryActivity is the programatic creation and addition of Views. The summary list can’t be defined in the layout XML because the number is dynamic. Instead I simply define the TableLayout then programatically add TableRows. This can be seen in the following snippet:

 

privatevoid addTableRow(String questionNum, String question, String answer, String attempts, String time){

TableRow newRow = new TableRow(this);

addTextViewToRow(newRow, questionNum, true);

addTextViewToRow(newRow, question + (answer!=null && answer.length() > 0 ? ” = “ + answer : “”), true);

addTextViewToRow(newRow, attempts, false);

addTextViewToRow(newRow, time, false);

emailBodyBuilder.append(“\n”);

rootView.addView(newRow);

}

privatevoid addTextViewToRow(TableRow row, String text, boolean leftAlign){

TextView textView = new TextView(this);

textView.setText(text);

LayoutParams layout = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);

layout.setMargins(0, 0, 15, 0);

textView.setLayoutParams(layout);

textView.setGravity(leftAlign ? Gravity.LEFT : Gravity.RIGHT);

row.addView(textView);

emailBodyBuilder.append(text + ” | “);

}

 

 

Things I’d like to change:

 

      1. Clean up the answer tracking code. I threw this in last minute without think through the architecture. I also pretty much stopped commenting when I got to the Summary Activity.
      2. Refactor the validation code. The validation for the setup screen got messy quick. I imagine there are better ways to handle input validation in Anroid
      3. Add more subject options. I want to add a Spelling subject instead of offering only math problems.
      4. Change the feedback dialogs to dismiss on touch instead of after 2 seconds. I’ve had a number of people test the app and all of them expect the feedback dialog (the green checkmark/red x) to disappear when they touch it instead of after a set time. Making this change would actually simplify the code a bit because there would be no need to hanlde messages in the Handler.
      5. Change the UI design. There are issue with the UI. Because input is always needed, the onscreen keyboard is almost always showing…which covers most of the UI in an annoying sort of way.
      6. Add more user customization. I’d like to be able to add options to adjust how the answers are rounded. I’d also like to make it an option to include decimals in the randomly generated numbers. Problems with more than 2 numbers would also be nice.

 

All in all , I’m pretty happy with how the app turned out. I’m going to make the above changes over the next few weeks, then hopefully release to the Android Market.