从Android应用程序的第二个线程更新视图

时间:2014-07-24 19:37:49

标签: java android multithreading android-asynctask android-handler

在我的申请中,有两件事情同时发生。活动中有一个时钟指针ImageView,它不断被转动,用户也可以按下操作栏按钮。更新时钟的手会大大降低应用程序的性能,按钮需要几秒钟才能响应。我需要能够在另一个线程上运行时钟旋转,但到目前为止我无法做到这一点。

我尝试的第一件事是使用Handler

class MainActivity extends ActionBarActivity() {

  Handler handler;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    ...

    handler = new Handler();
    startRotation();
  }

  private void startRotation() {
    Runnable r = new Runnable() {
      // do stuff to the UI here
    };

    handler.postDelayed(r, 100);
  }

}

但是因为它在MainActivity的线程上运行,所以它减慢了一切。

接下来,我使用了AsyncTask,但您无法在不调用的情况下从AsyncTask更新UI:

MainActivity.this.runOnUiThread(new Runnable() {});

它仍然在主线程上运行并减慢了应用程序。

所以我的目标是:能够在一个线程上完全更新时钟的手,以便主线程仅用于用户交互,这样它们都能顺利运行。

谢谢

编辑:

旋转时钟分针的代码(每100毫秒更新一次):

Runnable r = new Runnable() {

  ImageView minute_hand = (ImageView) findViewById(R.id.clock_hand_minute);
  Calendar c = Calendar.getInstance();
  float angle = 360f * ((float) c.get(Calendar.MINUTE) / 60f);
  // minSdk is 11, so this works:
  minute_hand.setRotation(angle);

};

1 个答案:

答案 0 :(得分:1)

如果您正在执行此代码:

ImageView minute_hand = (ImageView) findViewById(R.id.clock_hand_minute);
Calendar c = Calendar.getInstance();
float angle = 360f * ((float) c.get(Calendar.MINUTE) / 60f);
minute_hand.setRotation(angle);

每100毫秒,然后我说它有点矫枉过正。

一般情况下,请注意,由于此代码每隔100毫秒在UI线程中运行,因此消耗的时间片将从UI响应用户交互所需的时间中删除。因此,它应该尽可能快!

首先,您应该将findViewById(R.id.clock_hand_minute)代码移到runnable之外。在开始时调用它应该就足够了,因为视图不会改变。

其次,当一分钟过去时,分针移动6度,这是正确的。但是,您每100毫秒或每分钟600次这样做。这意味着视图正在针对每次(百分之一度)的非常小旋转进行更新,这些旋转可能几乎肉眼看不见,但在绘制方面耗时。

如果设置更新角度的最小阈值,可能会好得多。像

这样的东西
if (angle - lastAngle > THRESHOLD)
    minute_hand.setRotation(angle);