如何用线程构建我的Android计时器应用程序?

时间:2012-01-31 10:55:38

标签: android

我正在尝试为Android创建一个简单的锻炼计时器。用户创建包含总持续时间,总休息时间等信息的WorkoutPlan,应用程序将显示每秒更新的计时器。

开始时非常简单,但我正在尝试尽可能正确地构建应用程序,即分离关注点,正确的技术,响应式UI,确保计时器准确等等。

这是我到目前为止的简化:

WorkoutPlan,用户可以将不同的锻炼计划加载/保存到计时器

public class WorkoutPlan {
    public long duration;
}

TimerThread,此类实现Runnable,它在构造函数中引入WorkoutPlan,启动/停止,显示已用时间。

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 > 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();
            }
        }
    }
}

TimerView,显示已用时间的自定义视图

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();
        }        
    }
}

最后,WorkoutTimer,启动它的活动

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();
    }
}

几个问题:

  1. 哪里是创建WorkoutPlan对象的最佳位置?目前已在TimerView完成。是否应该在WorkoutTimer活动中完成?如果是,我如何将WorkoutPlan对象传递给TimerView
  2. 应用程序第一次运行正常,但是当我进入主屏幕然后第二次返回应用程序时崩溃。是什么导致它崩溃?它是theading?
  3. 目前我在新Handler中使用了Thread。这样可以或TimerTask会更好吗?哪个是开始该主题的最佳位置?
  4. 我是否正确将所有线程代码放入TimerView?感觉他们应该在别的地方。
  5. 我是否正确添加同步到TimerThread
  6. 中的所有方法
  7. 我正在尝试尽可能正确地创建此应用。如果我的技术有任何改进,或者我做错了什么,请告诉我。

1 个答案:

答案 0 :(得分:0)

如果你问的是风格,那么非常糟糕的风格就是在某些变体中使用“timer”这个词来实现不是Timer,而是完全不同的类,Handler。使用其他名称。现在代码几乎不可读。