Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to structure my Android timer app with thread?
    primarykey
    data
    text
    <p>I'm trying to create a simple Workout Timer for Android. The user creates a <code>WorkoutPlan</code> containing info such as total duration, total rest time, etc, the app will display a timer that updates every second.</p> <p>Pretty simple to begin with, but I'm trying to build the app as properly as possible, i.e. separation of concern, correct techniques, responsive UI, ensure the timer will be accurate, etc.</p> <p>Here's a simplification of what I have so far:</p> <p><code>WorkoutPlan</code>, the user can load/save different workout plans to the timer</p> <pre><code>public class WorkoutPlan { public long duration; } </code></pre> <p><code>TimerThread</code>, this class implements <code>Runnable</code>, it takes in a <code>WorkoutPlan</code> in the constructor, start/stop, shows elapsed time.</p> <pre><code>public class TimerThread implements Runnable { public boolean running = false; private long lastStartTime; private long savedTime; private WorkoutPlan plan; private Handler handler; public TimerThread(WorkoutPlan p, Handler h) { plan = p; handler = h; } public synchronized void start() { lastStartTime = System.currentTimeMillis(); running = true; } public synchronized void pause() { savedTime = elapsedTime(); lastStartTime = 0; running = false; } public synchronized long elapsedTime() { if (lastStartTime == 0) { return savedTime; } else { return savedTime + (System.currentTimeMillis() - lastStartTime); } } public synchronized String currTimeStr() { //format elapsed time in seconds to hh:mm:ss format long elapsed = elapsedTime() / 1000; long h = elapsed / 3600; long m = (elapsed % 3600) / 60; long s = elapsed % 60; if (h &gt; 0) { return String.format("%02d:%02d:%02d", h, m, s); } else { return String.format("%02d:%02d", m, s); } } @Override public void run() { while (running) { try { handler.sendMessage(handler.obtainMessage()); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } </code></pre> <p><code>TimerView</code>, the custom view that displays the elapsed time</p> <pre><code>public class TimerView extends View { private final Paint mBg; private final Paint mText; private WorkoutPlan plan; private TimerThread timer; private Thread thread; private Handler handler = new TimerHandler(); public TimerView(Context context, AttributeSet attrs) { super(context, attrs); plan = new WorkoutPlan(); timer = new TimerThread(plan, handler); thread = new Thread(timer); mBg = new Paint(); mBg.setColor(getResources().getColor(R.color.bg_default)); mText = new Paint(); mText.setColor(getResources().getColor(R.color.text)); } public void start() { timer.start(); thread.start(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //draw current time and current round canvas.drawText(timer.currTimeStr(), 0, 50, mText); } private class TimerHandler extends Handler { @Override public void handleMessage(Message msg) { super.handleMessage(msg); invalidate(); } } } </code></pre> <p>Finally, <code>WorkoutTimer</code>, the activity that starts it off</p> <pre><code>public class WorkoutTimer extends Activity { private TimerView mTimer; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.timer); mTimer = (TimerView) findViewById(R.id.timer_view); } @Override protected void onStart() { super.onStart(); mTimer.start(); } } </code></pre> <p>A couple of questions:</p> <ol> <li>Where's the best place to create the <code>WorkoutPlan</code> object? Currently it's done in <code>TimerView</code>. Should it be done in the <code>WorkoutTimer</code> activity instead? If yes, how do I pass the <code>WorkoutPlan</code> object to <code>TimerView</code>?</li> <li>The app works fine the first time, but crashes when I go to the home screen then back to the app the second time. What's causing it to crash? Is it the theading?</li> <li>Currently I'm using a <code>Handler</code> in a new <code>Thread</code>. Is this ok or would a <code>TimerTask</code> be better? Where's the best place to start the thread?</li> <li>Am I correct to put all the threading code in <code>TimerView</code>? It feels like they should be somewhere else.</li> <li>Am I correct to add synchronized to all the methods in <code>TimerThread</code>?</li> <li>I'm trying to create this app as properly as I can for practice. Please let me know if there's any improvements in technique I should make, or if I'm doing something incorrectly.</li> </ol>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload