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

Android 使用多线程时如何避免重新创建线程,android,multithreading,Android,Multithreading,我的主要目的是:每10分钟,应用程序就会同步服务器上的时间。然后,时钟将从从服务器获取的时间开始,而倒计时时钟将显示到下一次同步的剩余时间 我的代码如下。线程似乎每10分钟重新创建一次,因此时钟显示错误。但是,我不知道如何修复它。请帮帮我。谢谢 public class MainActivity extends Activity { private AnalogClockView analogClockView; private FrameLayout analogLayout;

我的主要目的是:每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);               
        }
     }   
}
公共类MainActivity扩展活动{
私有模拟时钟视图模拟时钟视图;
私有框架布局;
私人长现在;
私有ClockAsyncTask mClockAsyncTask;
专用倒计时器mCountDownTimer=新倒计时器(10*60*1000,1000){
@凌驾
公共无效onFinish(){
mClockAsyncTask=(ClockAsyncTask)新的ClockAsyncTask();
mclocksynctask.execute();
}
@凌驾
公共void onTick(长毫秒未完成){
//TODO自动生成的方法存根
analogClockView.updateTime();
analogClockView.postInvalidate();
}
};
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
analogLayout=(FrameLayout)findViewById(R.id.analogLayout);
mCountDownTimer.start();
}
@凌驾
公共布尔onCreateOptions菜单(菜单){
//为菜单充气;这会将项目添加到操作栏(如果存在)。
getMenuInflater().充气(R.menu.main,menu);
返回true;
}
私有类ClockAsyncTask扩展了AsyncTask{
@凌驾
受保护对象doInBackground(对象…arg0){
getNTPTime();
返回null;
}
@凌驾
受保护的void onPostExecute(对象结果){
analogClockView=新的analogClockView(MainActivity.this,现在是analogLayout.getWidth()/2,analogLayout.getHeight()/2);
analogLayout.removeAllViews();
analogLayout.addView(analogClockView);
}
}
public void getNTPTime(){
SntpClient=新的SntpClient();
if(client.requestTime(“0.ubuntu.pool.ntp.org”,1000)){
now=client.getNtpTime()+SystemClock.elapsedRealtime()
-client.getntoptimereference();
当前日历=Calendar.getInstance();
当前.setTimeInMillis(现在);
}
}   
}

问题在于,代码将用于线程的相同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回调。)


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

[倒计时计时器安排]倒计时直到将来某个时间,并定期通知沿途的时间间隔

然后,流程大致如下所示:

  • 创建一个倒计时,并使用剩余时间更新UI,每次单击
    onTick
    。当倒计时结束并触发
    onFinish
    事件时,创建一个新的异步任务

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

  • 无限期地重复这个循环;确保根据需要取消任何倒计时


为什么线程使用异步任务?还有,为什么不使用定时器/倒计时器?@user2864740:当我使用SntpClient从服务器获取时间时,当我不将它放入AsyncTask时,它会导致异常。另外,这篇文章说定时器不好,所以,我必须在我的代码中将线程改为倒计时?从服务器获取时间后,时钟仍然自行运行,我们不使用线程?代码中的显式线程是无用的。Runnable用于线程和延迟回发是令人困惑的,因为它仅在实例上第一次调用
run
方法时位于新线程中。我建议使用倒计时,因为它很好地封装了逻辑:“经常这样做”时钟是怎么回事?每10分钟,mClockAsyncTask=(ClockAsyncTask)new ClockAsyncTask();可以吗?此外,当我想停止倒计时计时器以手动同步时间时,我该如何做?请参阅
如果(倒计时运行){
(但是,该表达式是受控的,我建议添加一个带有标志的“停止”或“取消”方法);但是如果你使用了倒计时,那么你可以
取消它。。是的,我现在正在尝试使用倒计时。但是当我更新时钟的GUI时,我仍然使用线程?
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();
}