android - 使用多线程时如何避免重新创建线程

标签 android multithreading

我的主要目的是:应用程序每 10 分钟同步一次服务器上的时间。然后,时钟将从服务器获取的时间开始计时,而倒计时时钟将显示剩余时间,直到下一次同步。

我的代码如下。似乎线程每 10 分钟重新创建一次,所以时钟显示错误。但是,我不知道如何解决它。请帮我。谢谢!

public class MainActivity extends Activity {
    private AnalogClockView analogClockView;
    private FrameLayout analogLayout;
    private long now;
    private ClockAsyncTask mClockAsyncTask;

    private CountDownTimer mCountDownTimer = new CountDownTimer(10*60*1000, 1000) {
        @Override 
        public void onFinish() {
            mClockAsyncTask = (ClockAsyncTask) new ClockAsyncTask();
            mClockAsyncTask.execute();                  
        }

        @Override
        public void onTick(long millisUntilFinished) {
            // TODO Auto-generated method stub  
            analogClockView.updateTime();
            analogClockView.postInvalidate();
        }
      };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);     
        analogLayout = (FrameLayout) findViewById(R.id.analogLayout); 
        mCountDownTimer.start();        
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    private class ClockAsyncTask extends AsyncTask<Object, Object, Object> {            
        @Override
        protected Object doInBackground(Object... arg0) {
            getNTPTime();
            return null;
        }

        @Override
        protected void onPostExecute(Object result) {
            analogClockView = new AnalogClockView(MainActivity.this, now, analogLayout.getWidth()/2, analogLayout.getHeight()/2);
            analogLayout.removeAllViews();
            analogLayout.addView(analogClockView);
        }
    }

     public void getNTPTime(){
        SntpClient client = new SntpClient();
        if (client.requestTime("0.ubuntu.pool.ntp.org", 1000)) {
            now = client.getNtpTime() + SystemClock.elapsedRealtime()
                    - client.getNtpTimeReference();
            Calendar current = Calendar.getInstance();
            current.setTimeInMillis(now);               
        }
     }   
}

最佳答案

问题是代码将用于线程的 相同 Runnable 返回 无休止地馈入 postDelayed。线程只运行很短的时间,但代码会不断发布消息(并且每条消息都会发布另一条消息(并且每条消息都会发布..))。

然后,一种解决方案是使用变量来决定何时发布另一个事件。

// Not really a "Thread"
public class CountdownRunner implements Runnable {
    public void run() {
        if (countdownRunning) {
            MainActivity.this.updateHandler.sendEmptyMessage(0);
            // STOP calling when then the countdown is over
            // The fundamental problem is this series of delayed postbacks
            // is never sopped in the original code.
            updateHandler.postDelayed(this, 1000);
        }
    } 
    public void cancel() {
       // ..
    }
}

此外,放弃创建新线程,因为显式线程在这里没有任何用处:提供的 Runnable 的 run 方法仅在线程上调用一次,然后是线程死了。 (run 方法的后续调用在 UI 线程上以响应 postDelayed 回调。)

private CountdownRunner countdown;

protected void onPostExecute(Object result) {
    // Start the countdown with the time from the server,
    // cancelling the previous countdown as required.
    if (countdown != null) {
        countdown.cancel();
    }
    // No "new Thread"! this is running on the UI thread and all
    // subsequent executions of run for this instance will also be
    // on the UI thread in the postDelayed postback.
    countdown = new CountdownRunner();
    countdown.run();
}

虽然上面解释了问题,但我建议简单地使用 CountDownTimer因为它很好地封装了逻辑:

[A CountDownTimer schedules] a countdown until a time in the future, with regular notifications on intervals along the way.

然后流程一般是这样的:

  • 创建一个 CountDownTimer 并在每次 onTick 时用剩余时间更新 UI。当倒计时结束并且 onFinish 事件触发时,创建一个新的 AsyncTask。

  • 让 AsyncTask(即 ClockAsyncTask)在 doInBackground 方法中下载时间。在 onPostExecute 方法中,创建一个新的 CountDownTimer。

  • 无限期地重复这个循环;确保适当取消任何 CountDownTimers。

关于android - 使用多线程时如何避免重新创建线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24094672/

相关文章:

c# - 将局部变量传递给 .net 中的另一个线程

java - 在非服务器应用程序中嵌入 ServerSockets

android - 图片浏览器滑动

android - 显示软键盘时更改布局

java - 如何使用 ConnectionService 获取 Call UI Presentation

java - 安卓: Realm +改造2+Gson

Android 项目在部署时挂起

java - 设置准备好的语句参数时出现 NullPointerException

java - 静态初始化器和安全发布

multithreading - 相当于 RUSAGE_THREAD Darwin ?