I'm new to Java and Android. While I've created a project that seems to work, I'd like some opinions on how to make it better.
The app is going to be used as an interval workout timer/music player for Android devices. I know there's a ton of these already, but I thought it'd be a good way to learn the language, and it's useful for me. I haven't gotten the music player piece working yet. I was thinking of letting you select between selecting a playlist to play or using the 8tracks.com API to play streaming music. Comments are welcome, too.
The code can be seen in full in this Github.
Here's the main package:
package com.blueflamesys.workoutstopwatch;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class WorkoutStopwatch extends Activity implements OnClickListener {
private static final String TAG = "WorkoutMain";
private static final String API_KEY = "30eee341eb88a9647b40d187faf508b50ca318d9";
private boolean timerRunning, isPaused = false;
private long millisLeft = 0;
private WorkoutTimer workoutTimer;
private enum CounterState {
UNKNOWN(0),
WORKOUT(1),
REST(2);
private int stateValue;
CounterState(int state) {
this.stateValue = state;
}
public int getStateValue() {
return stateValue;
}
public void setStateValue(int state) {
this.stateValue = state;
}
}
CounterState state = CounterState.WORKOUT;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.workout_stopwatch);
// Set up OnClickListeners
((Button) findViewById(R.id.start_button)).setOnClickListener(this);
((Button) findViewById(R.id.pause_button)).setOnClickListener(this);
((Button) findViewById(R.id.reset_button)).setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch(v.getId()) {
case R.id.start_button:
Log.d(TAG, "clicked on Start Button");
if (!isPaused && !timerRunning) {
Log.d(TAG, "Wasn't paused and wasn't running...");
timerRunning = true;
// If the state is unknown, set it to Workout first
int State = state.getStateValue();
if (State == 0) {
state.setStateValue(1);
}
workoutTimer = new WorkoutTimer(50);
workoutTimer.start();
}
if (isPaused) {
timerRunning = true;
this.resumeTimer();
Log.d(TAG, "Was paused resumed timer...");
}
break;
case R.id.pause_button:
Log.d(TAG, "clicked on Pause Button");
if (timerRunning) {
timerRunning = false;
this.pauseTimer();
Log.d(TAG, "Paused timer...");
}
break;
case R.id.reset_button:
Log.d(TAG, "clicked on Reset Button");
if (!timerRunning) {
Log.d(TAG, "Wasn't running...");
isPaused = false;
TextView digital_display = (TextView) findViewById(R.id.digital_display);
digital_display.setText("00:00.0");
}
break;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.stopwatch_settings, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.settings:
startActivity(new Intent(this, Prefs.class));
return true;
case R.id.about:
Intent i = new Intent(this, About.class);
startActivity(i);
break;
}
return false;
}
public void pauseTimer() {
isPaused = true;
SharedPreferences workoutTimerDB = getSharedPreferences("workoutTimerDB", MODE_PRIVATE);
SharedPreferences.Editor edit = workoutTimerDB.edit();
edit.putLong("millisLeft", (Long)this.millisLeft);
edit.commit();
workoutTimer.cancel();
}
public void resumeTimer() {
if (isPaused) {
isPaused = false;
SharedPreferences workoutTimerDB = getSharedPreferences("workoutTimerDB", MODE_PRIVATE);
millisLeft = workoutTimerDB.getLong("millisLeft", 0);
workoutTimer = new WorkoutTimer(millisLeft, 50);
workoutTimer.start();
}
}
private class WorkoutTimer extends CountDownTimer{
public WorkoutTimer(long interval) {
super(getThisTime(), interval);
Log.d(TAG, "WorkoutTimer Constructed with interval only...");
}
public WorkoutTimer(long millis, long interval) {
super(millis, interval);
Log.d(TAG, "WorkoutTimer Constructed with both...");
}
public void onFinish() {
int State = state.getStateValue();
int roundsLeft = 0;
if (State == 1) {
state.setStateValue(2);
} else {
state.setStateValue(1);
decrementRounds();
}
Log.d(TAG, "WorkoutState = " + state.getStateValue());
try {
TextView numOfRounds = (TextView) findViewById(R.id.number_of_rounds);
roundsLeft = Integer.parseInt(numOfRounds.getText().toString());
} catch(NumberFormatException nfe) {
roundsLeft = 999;
}
if (roundsLeft > 0) { // If there's still rounds, start the timer.
workoutTimer = new WorkoutTimer(100);
workoutTimer.start();
} else { // Stop the timer and reset the display
workoutTimer.cancel();
TextView digital_display = (TextView) findViewById(R.id.digital_display);
digital_display.setText("00:00.0");
}
}
public void onTick(long millisUntilFinished) {
final long minutes_left = ((millisUntilFinished / 1000) / 60);
final long seconds_left = (millisUntilFinished / 1000) - (minutes_left * 60);
final long millis = millisUntilFinished % 100;
final String time_left = String.format("%02d:%02d.%01d", minutes_left, seconds_left,
millis/10);
TextView digital_display = (TextView) findViewById(R.id.digital_display);
digital_display.setText(time_left);
millisLeft = millisUntilFinished;
}
@Override
protected void finalize() throws Throwable {
super.finalize();
Log.d(TAG, "Object destroyed");
}
}
private long getThisTime() {
long time = 0;
TextView workout_time = (TextView) findViewById(R.id.workout_time);
TextView rest_time = (TextView) findViewById(R.id.rest_time);
switch(state.getStateValue()) {
case 1:
try {
time = Integer.parseInt(workout_time.getText().toString());
} catch(NumberFormatException nfe) {
time = 999;
}
Log.d(TAG, "Workout time = " + time);
break;
case 2:
try {
time = Integer.parseInt(rest_time.getText().toString());
} catch(NumberFormatException nfe) {
time = 999;
}
Log.d(TAG, "Rest time = " + time);
break;
case 0:
time = 0;
break;
}
return time * 1000;
}
private void decrementRounds() {
int roundsLeft = 2;
TextView numOfRounds = (TextView) findViewById(R.id.number_of_rounds);
try {
roundsLeft = Integer.parseInt(numOfRounds.getText().toString());
} catch(NumberFormatException nfe) {
roundsLeft = 999;
}
roundsLeft -= 1;
numOfRounds.setText(String.valueOf(roundsLeft));
Log.d(TAG, "set rounds to = " + roundsLeft);
}
}
Don't hold back, and feel free to ask any questions or give any criticisms.