Reputation: 1111
I am currently working on my very first, complete Android app. I am developing a Maths Brain Trainer Game so I am in need of a countdown timer. Hence, I am using Android's CountDownTimer to build it.
The following is the Java code of my GameActivity.java class which I am using to control my game play.
package lk.iit.mobiletechnology.mathematicsbraintrainer;
import java.util.concurrent.TimeUnit;
import lk.iit.mobiletechnology.mathematicsbraintrainer.entity.Challenge;
import lk.iit.mobiletechnology.mathematicsbraintrainer.entity.Game;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@SuppressLint("NewApi")
public class GameActivity extends ActionBarActivity {
private Game game;
private Challenge currentChallenge;
private int questionCount;
private TextView timeView;
private TextView question;
private EditText inputField;
private static final String TAG = "Brain Trainer" ;
private static final int MAXIMUM_QUESTIONS = 10;
public static final String KEY_DIFFICULTY = "lk.iit.mobiletechnology.mathematicsbraintrainer.difficulty";
public static final int DIFFICULTY_NOVICE = 0;
public static final int DIFFICULTY_EASY = 1;
public static final int DIFFICULTY_MEDIUM = 2;
public static final int DIFFICULTY_GURU = 3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
int difficultyLevel = this.getIntent().getIntExtra(KEY_DIFFICULTY, GameActivity.DIFFICULTY_NOVICE);
this.game = new Game(GameActivity.MAXIMUM_QUESTIONS, difficultyLevel);
this.questionCount = 0;
this.question = (TextView)(this.findViewById(R.id.question_text));
currentChallenge = this.game.getChallenges().get(questionCount);
question.setText(currentChallenge.toString());
this.timeView = (TextView)(this.findViewById(R.id.time_text));
timeView.setText("00:10");
final CountDownMachine timer = new CountDownMachine(10000, 1000);
timer.start();
this.setButtonClickListener();
}
private void setButtonClickListener() {
Button testButton = (Button)(findViewById(R.id.test_button));
inputField = (EditText)(findViewById(R.id.question_input));
testButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
double inputValue = Double.parseDouble(inputField.getText().toString());
ImageView imageView = (ImageView)(findViewById(R.id.answer_feedback));
Drawable drawable;
if(questionCount < 10) {
if(currentChallenge.correctAnswer(inputValue)) {
drawable = getResources().getDrawable(R.drawable.fixed_correct_image);
imageView.setImageDrawable(drawable);
}
else {
drawable = getResources().getDrawable(R.drawable.fixed_wrong_image);
imageView.setImageDrawable(drawable);
}
questionCount++;
if(questionCount == 5) {
//Intent intent = new Intent(, UserEntryActivity.class);
finish();
}
currentChallenge = game.getChallenges().get(questionCount);
question.setText(currentChallenge.toString());
inputField.setText(" ?");
}
}
});
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@SuppressLint("NewApi")
public class CountDownMachine extends CountDownTimer {
public CountDownMachine(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@SuppressLint("NewApi")
@Override
public void onTick(long millisUntilFinished) {
long timeRemaining = millisUntilFinished;
String text = String.format("%02d:%02d", (TimeUnit.MILLISECONDS.toMinutes(timeRemaining) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(timeRemaining))), (TimeUnit.MILLISECONDS.toSeconds(timeRemaining) - (TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(timeRemaining)))));
timeView.setText(text);
}
@Override
public void onFinish() {
ImageView imageView = (ImageView)(findViewById(R.id.answer_feedback));
Drawable drawable;
if(!(inputField.getText().toString().equals(""))) {
double inputValue = Double.parseDouble(inputField.getText().toString());
if(questionCount < 10) {
if(currentChallenge.correctAnswer(inputValue)) {
drawable = getResources().getDrawable(R.drawable.fixed_correct_image);
imageView.setImageDrawable(drawable);
}
else {
drawable = getResources().getDrawable(R.drawable.fixed_wrong_image);
imageView.setImageDrawable(drawable);
}
}
}
else {
drawable = getResources().getDrawable(R.drawable.fixed_wrong_image);
imageView.setImageDrawable(drawable);
}
questionCount++;
if(questionCount == 5) {
finish();
}
currentChallenge = game.getChallenges().get(questionCount);
question.setText(currentChallenge.toString());
inputField.setText(" ?");
timeView.setText("00:10");
}
}
}
The associated activity_game.xml which defines the layout is as follows:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:background="@color/background"
tools:context="lk.iit.mobiletechnology.mathematicsbraintrainer.GameActivity" >
<TextView
android:id="@+id/time_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:textSize="15sp"
android:textStyle="bold"
android:textColor="#000"
/>
<TextView
android:id="@+id/question_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:textSize="15sp"
android:textStyle="bold"
android:textColor="#000"
android:layout_below="@+id/time_text"
/>
<EditText
android:id="@+id/question_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="numberDecimal|numberSigned"
android:text=" ?"
android:layout_below="@+id/question_text"
android:background="#fff"
/>
<ImageView
android:id="@+id/answer_feedback"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="@dimen/image_text_gap"
android:layout_below="@+id/question_input"
android:layout_centerHorizontal="true"
/>
<Button
android:id="@+id/test_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test"
android:layout_below="@+id/answer_feedback"
android:layout_centerHorizontal="true"
/>
</RelativeLayout>
Note that this java class still does not cover the entire requirements but it is capable of firing 10 questions during each game play. I have introduced the timer but since the call to timer.start() method I am constantly getting the following exception:
Android IllegalAccessError java.util.concurrent.TimeUnit.toMinutes
Since I am new to this field of development and it is quite rare to find a proper solution to this I would be grateful if somebody can help me by explaining why I am getting this and what kind of solution(s) exist.
This is the logcat content of the exception I am getting:
03-06 01:52:59.328: D/AndroidRuntime(278): Shutting down VM
03-06 01:52:59.328: W/dalvikvm(278): threadid=1: thread exiting with uncaught exception (group=0x4001d800)
03-06 01:52:59.348: E/AndroidRuntime(278): FATAL EXCEPTION: main
03-06 01:52:59.348: E/AndroidRuntime(278): java.lang.IllegalAccessError: tried to access method java.util.concurrent.TimeUnit.toMinutes:(J)V from class lk.iit.mobiletechnology.mathematicsbraintrainer.GameActivity$CountDownMachine
03-06 01:52:59.348: E/AndroidRuntime(278): at lk.iit.mobiletechnology.mathematicsbraintrainer.GameActivity$CountDownMachine.onTick(GameActivity.java:108)
03-06 01:52:59.348: E/AndroidRuntime(278): at android.os.CountDownTimer$1.handleMessage(CountDownTimer.java:124)
03-06 01:52:59.348: E/AndroidRuntime(278): at android.os.Handler.dispatchMessage(Handler.java:99)
03-06 01:52:59.348: E/AndroidRuntime(278): at android.os.Looper.loop(Looper.java:123)
03-06 01:52:59.348: E/AndroidRuntime(278): at android.app.ActivityThread.main(ActivityThread.java:4627)
03-06 01:52:59.348: E/AndroidRuntime(278): at java.lang.reflect.Method.invokeNative(Native Method)
03-06 01:52:59.348: E/AndroidRuntime(278): at java.lang.reflect.Method.invoke(Method.java:521)
03-06 01:52:59.348: E/AndroidRuntime(278): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
03-06 01:52:59.348: E/AndroidRuntime(278): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
03-06 01:52:59.348: E/AndroidRuntime(278): at dalvik.system.NativeStart.main(Native Method)
Upvotes: 2
Views: 242
Reputation: 8774
Don't use TimeUnit to convert millis into seconds, minutes and so on, just do it yourself.
int seconds = (millis / 1000) % 60;
int minutes = millis / (1000 * 60);
Apparently you get this error when TimeUnit is not available in your runtime, see here:
Android IllegalAccessError java.util.concurrent.TimeUnit.toHours
Upvotes: 2