Android Handler会冻结GUI

时间:2012-11-14 17:29:38

标签: android timer handler

我正在尝试将PC Java程序移植到Android平台。 PC应用程序使用Swing.Timer每秒触发更新。在被调用时,关联的侦听器从数据库获取新数据,然后使用Graphics2D更新/重绘屏幕。我已经学会了如何使用Android的Canvas来绘制与PC应用程序相同的东西。现在我正在尝试学习如何在Android中使用等效的Timer。不幸的是,在Android平台上,事情似乎并不那么简单。有计时器,处理程序,AlarmManagers和AsyncTasks。似乎AsyncTasks和AlarmManagers更适合一次(重任?)任务(对吗?错误?)关于定时器和处理程序,我看过很多帖子说不使用Timer,而是使用Handler。我在Web上的某处找到了下面代码中使用的方法并尝试了它。它似乎应该做我想要的,但每当我点击停止按钮时它会挂起GUI。有谁知道为什么会这样做?

感谢一百万 比尔

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    dateFormat = new SimpleDateFormat(dateFormatString);
    mHandler = new Handler();
    mUpdateTimeTask = new MyRunnable();
    Button button = (Button) findViewById(R.id.start_button);
    button.setOnClickListener(new MyStartListener());
    button = (Button) findViewById(R.id.stop_button);
    button.setOnClickListener(new MyStopListener());
}

class MyStartListener implements View.OnClickListener {
    public void onClick(View v) {
        if (startUptimeMillis == 0L) {
            startUptimeMillis = SystemClock.uptimeMillis();
            mHandler.removeCallbacks(mUpdateTimeTask);
            mHandler.postDelayed(mUpdateTimeTask, 100);
        }
    }
};

class MyStopListener implements View.OnClickListener {
    public void onClick(View v) {
        mHandler.removeCallbacks(mUpdateTimeTask);
   }
};

class MyRunnable implements Runnable {
    public void run() {
        final long start = startUptimeMillis;
        long millis = SystemClock.uptimeMillis() - start;
        int seconds = (int) (millis / 1000);
        int minutes = seconds / 60;
        seconds = seconds % 60;
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        TextView tv = (TextView) findViewById(R.id.time_textView);
        tv.setText(dateFormat.format(calendar.getTime()));
        mHandler.postAtTime(this, (((minutes * 60) + seconds + 1) * 1000));
    }
 };

编辑: 问题是postAtTime需要一个绝对时间来启动,而不是我的例子正在使用的延迟。 (See postAtTime here) 所以我用下面的代码替换了上面的所有时序代码,它做了我想要的!!:

long millis = SystemClock.uptimeMillis();
mHandler.postAtTime(this, millis+1000);

1 个答案:

答案 0 :(得分:1)

我不知道这会如何挂起你的应用程序,除非你的意思是开始按钮不再起作用...也许你想将它添加到你的停止监听器:

public void onClick(View v) {
    startUptimeMillis = 0l; // Reset startUptimeMillis
    mHandler.removeCallbacks(mUpdateTimeTask);
}

就Timers,AsyncsTask等而言......你是对的,在不久的将来在Android中编程事件的最好方法是使用Handler和Runnable。 AlarmManagers不适用于动画中的快速回调,AsyncTasks更适合重载计算。

我想提供一个更简单的更新Runnable:

class MyRunnable implements Runnable {
    public void run() {
        // You should make this a class variable and initialize it in onCreate(), 
        //   there is no need to search for the same View every second.
        TextView tv = (TextView) findViewById(R.id.time_textView);

        final long now = System.currentTimeMillis();
        tv.setText(dateFormat.format(now));
        mHandler.postAtTime(this, 1000 - (now - start) % 1000); // Accounts for millisecond offsets over time
        // mHandler.postDelayed(this, 1000); // Effected by minute offsets
    }
};