Таймер Android? Как?

Может кто-нибудь привести простой пример обновления текстового поля каждую секунду или около того?

Я хочу сделать летающий шар и мне нужно вычислять / обновлять координаты шара каждую секунду, поэтому мне нужен какой-то таймер.

Я ничего не получаю отсюда.

24 ответа

Решение

Хорошо, так как это еще не выяснено, есть 3 простых способа справиться с этим. Ниже приведен пример, показывающий все 3, а внизу пример, показывающий только тот метод, который я считаю предпочтительным. Также не забудьте очистить ваши задачи в onPause, сохраняя состояние при необходимости.


import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Handler.Callback;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class main extends Activity {
    TextView text, text2, text3;
    long starttime = 0;
    //this  posts a message to the main thread from our timertask
    //and updates the textfield
   final Handler h = new Handler(new Callback() {

        @Override
        public boolean handleMessage(Message msg) {
           long millis = System.currentTimeMillis() - starttime;
           int seconds = (int) (millis / 1000);
           int minutes = seconds / 60;
           seconds     = seconds % 60;

           text.setText(String.format("%d:%02d", minutes, seconds));
            return false;
        }
    });
   //runs without timer be reposting self
   Handler h2 = new Handler();
   Runnable run = new Runnable() {

        @Override
        public void run() {
           long millis = System.currentTimeMillis() - starttime;
           int seconds = (int) (millis / 1000);
           int minutes = seconds / 60;
           seconds     = seconds % 60;

           text3.setText(String.format("%d:%02d", minutes, seconds));

           h2.postDelayed(this, 500);
        }
    };

   //tells handler to send a message
   class firstTask extends TimerTask {

        @Override
        public void run() {
            h.sendEmptyMessage(0);
        }
   };

   //tells activity to run on ui thread
   class secondTask extends TimerTask {

        @Override
        public void run() {
            main.this.runOnUiThread(new Runnable() {

                @Override
                public void run() {
                   long millis = System.currentTimeMillis() - starttime;
                   int seconds = (int) (millis / 1000);
                   int minutes = seconds / 60;
                   seconds     = seconds % 60;

                   text2.setText(String.format("%d:%02d", minutes, seconds));
                }
            });
        }
   };


   Timer timer = new Timer();
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        text = (TextView)findViewById(R.id.text);
        text2 = (TextView)findViewById(R.id.text2);
        text3 = (TextView)findViewById(R.id.text3);

        Button b = (Button)findViewById(R.id.button);
        b.setText("start");
        b.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Button b = (Button)v;
                if(b.getText().equals("stop")){
                    timer.cancel();
                    timer.purge();
                    h2.removeCallbacks(run);
                    b.setText("start");
                }else{
                    starttime = System.currentTimeMillis();
                    timer = new Timer();
                    timer.schedule(new firstTask(), 0,500);
                    timer.schedule(new secondTask(),  0,500);
                    h2.postDelayed(run, 0);
                    b.setText("stop");
                }
            }
        });
    }

    @Override
    public void onPause() {
        super.onPause();
        timer.cancel();
        timer.purge();
        h2.removeCallbacks(run);
        Button b = (Button)findViewById(R.id.button);
        b.setText("start");
    }
}

главное помнить, что пользовательский интерфейс может быть изменен только из основного потока пользовательского интерфейса, поэтому используйте обработчик или activity.runOnUIThread(Runnable r);

Вот то, что я считаю предпочтительным методом.


import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class TestActivity extends Activity {

    TextView timerTextView;
    long startTime = 0;

    //runs without a timer by reposting this handler at the end of the runnable
    Handler timerHandler = new Handler();
    Runnable timerRunnable = new Runnable() {

        @Override
        public void run() {
            long millis = System.currentTimeMillis() - startTime;
            int seconds = (int) (millis / 1000);
            int minutes = seconds / 60;
            seconds = seconds % 60;

            timerTextView.setText(String.format("%d:%02d", minutes, seconds));

            timerHandler.postDelayed(this, 500);
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_activity);

        timerTextView = (TextView) findViewById(R.id.timerTextView);

        Button b = (Button) findViewById(R.id.button);
        b.setText("start");
        b.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Button b = (Button) v;
                if (b.getText().equals("stop")) {
                    timerHandler.removeCallbacks(timerRunnable);
                    b.setText("start");
                } else {
                    startTime = System.currentTimeMillis();
                    timerHandler.postDelayed(timerRunnable, 0);
                    b.setText("stop");
                }
            }
        });
    }

  @Override
    public void onPause() {
        super.onPause();
        timerHandler.removeCallbacks(timerRunnable);
        Button b = (Button)findViewById(R.id.button);
        b.setText("start");
    }

}

Это просто! Вы создаете новый таймер.

Timer timer = new Timer();

Затем вы расширяете задачу таймера

class UpdateBallTask extends TimerTask {
   Ball myBall;

   public void run() {
       //calculate the new position of myBall
   }
}

А затем добавить новую задачу в таймер с некоторым интервалом обновления

final int FPS = 40;
TimerTask updateBall = new UpdateBallTask();
timer.scheduleAtFixedRate(updateBall, 0, 1000/FPS);

Отказ от ответственности: это не идеальное решение. Это решение с использованием класса Timer (по запросу OP). В Android SDK рекомендуется использовать класс Handler (в принятом ответе есть пример).

Если вам также нужно запустить код в потоке пользовательского интерфейса (а не в потоке таймера), загляните в блог: http://steve.odyfamily.com/?p=12

public class myActivity extends Activity {
private Timer myTimer;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.main);

    myTimer = new Timer();
    myTimer.schedule(new TimerTask() {          
        @Override
        public void run() {
            TimerMethod();
        }

    }, 0, 1000);
}

private void TimerMethod()
{
    //This method is called directly by the timer
    //and runs in the same thread as the timer.

    //We call the method that will work with the UI
    //through the runOnUiThread method.
    this.runOnUiThread(Timer_Tick);
}


private Runnable Timer_Tick = new Runnable() {
    public void run() {

    //This method runs in the same thread as the UI.               

    //Do something to the UI thread here

    }
};
}

Если вы просто хотите запланировать обратный отсчет до определенного времени в будущем с регулярными уведомлениями через определенные промежутки времени, вы можете использовать класс CountDownTimer, который доступен начиная с уровня API 1.

new CountDownTimer(30000, 1000) {
    public void onTick(long millisUntilFinished) {
        editText.setText("Seconds remaining: " + millisUntilFinished / 1000);
    }

    public void onFinish() {
        editText.setText("Done");
    }
}.start();

Это простой код для таймера:

Timer timer = new Timer();
TimerTask t = new TimerTask() {       
    @Override
    public void run() {

        System.out.println("1");
    }
};
timer.scheduleAtFixedRate(t,1000,1000);

Я думаю, что вы можете сделать это в Rx, например:

 timerSubscribe = Observable.interval(1, TimeUnit.SECONDS)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Action1<Long>() {
                @Override
                public void call(Long aLong) {
                      //TODO do your stuff
                }
            });

И отмените это как:

timerSubscribe.unsubscribe();

Rx Timer http://reactivex.io/documentation/operators/timer.html

Я удивлен, что нет ответа, который упомянул бы решение с RxJava2. Это действительно просто и предоставляет простой способ настройки таймера в Android.

Сначала вам нужно настроить зависимость от Gradle, если вы еще этого не сделали:

implementation "io.reactivex.rxjava2:rxjava:2.x.y"

(заменить x а также y с текущим номером версии)

Так как у нас есть простая, неповторяющаяся задача, мы можем использовать Completable объект:

Completable.timer(2, TimeUnit.SECONDS, Schedulers.computation())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(() -> {
            // Timer finished, do something...
        });

Для ПОВТОРНОЙ ЗАДАЧИ вы можете использовать Observable Аналогичным образом:

Observable(2, TimeUnit.SECONDS, Schedulers.computation())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(tick -> {
            // called every 2 seconds, do something...
        }, throwable -> {
            // handle error
        });

Schedulers.computation() гарантирует, что наш таймер работает в фоновом потоке и .observeOn(AndroidSchedulers.mainThread()) означает, что код, который мы запускаем после завершения таймера, будет выполнен в основном потоке.

Чтобы избежать нежелательных утечек памяти, вы должны отменить подписку, когда действие / фрагмент уничтожен.

Поскольку этот вопрос по-прежнему привлекает множество пользователей из поиска в Google (о таймере Android), я хотел бы вставить свои две монеты.

Прежде всего, класс Timer будет устаревшим в Java 9 (прочитайте принятый ответ).

Официальный рекомендуемый способ - использовать ScheduledThreadPoolExecutor, который является более эффективным и многофункциональным, что может дополнительно запланировать выполнение команд после заданной задержки или периодическое выполнение. Кроме того, это дает дополнительную гибкость и возможности ThreadPoolExecutor.

Вот пример использования простых функций.

  1. Создать службу исполнителя:

    final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1);
    
  2. Просто график вы работаете:

    final Future<?> future = SCHEDULER.schedule(Runnable task, long delay,TimeUnit unit);
    
  3. Теперь вы можете использовать future отменить задание или проверить, выполнено ли оно, например:

    future.isDone();
    

Надеюсь, вы найдете это полезным для создания задач в Android.

Полный пример:

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Future<?> sampleFutureTimer = scheduler.schedule(new Runnable(), 120, TimeUnit.SECONDS);
if (sampleFutureTimer.isDone()){
    // Do something which will save world.
}

Для кого хочет сделать это в котлине:

val timer = fixedRateTimer(period = 1000L) {
            val currentTime: Date = Calendar.getInstance().time
            runOnUiThread {
                tvFOO.text = currentTime.toString()
            }
        }

для остановки таймера вы можете использовать это:

timer.cancel()

у этой функции есть много других опций, попробуйте

      import kotlin.concurrent.fixedRateTimer

val timer = fixedRateTimer("Tag", false, 1000, 2500) { /* Your code here */ }

С Kotlin довольно просто

Это более простое решение, отлично работает в моем приложении.

  public class MyActivity extends Acitivity {

    TextView myTextView;
    boolean someCondition=true;

     @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.my_activity);

            myTextView = (TextView) findViewById(R.id.refreshing_field);

            //starting our task which update textview every 1000 ms
            new RefreshTask().execute();



        }

    //class which updates our textview every second

    class RefreshTask extends AsyncTask {

            @Override
            protected void onProgressUpdate(Object... values) {
                super.onProgressUpdate(values);
                String text = String.valueOf(System.currentTimeMillis());
                myTextView.setText(text);

            }

            @Override
            protected Object doInBackground(Object... params) {
                while(someCondition) {
                    try {
                        //sleep for 1s in background...
                        Thread.sleep(1000);
                        //and update textview in ui thread
                        publishProgress();
                    } catch (InterruptedException e) {
                        e.printStackTrace(); 

                };
                return null;
            }
        }
    }

Вы хотите, чтобы обновления вашего пользовательского интерфейса происходили в уже существующем потоке пользовательского интерфейса.

Лучший способ - использовать обработчик, который использует postDelayed для запуска Runnable после задержки (каждый запуск планирует следующий); очистить обратный вызов с помощью removeCallbacks.

Вы уже ищете правильное место, поэтому посмотрите на него еще раз, возможно, объясните, почему этот пример кода не тот, который вам нужен. (См. Также ту же статью в разделе Обновление интерфейса от таймера).

Вы также можете использовать аниматор для этого:

int secondsToRun = 999;

ValueAnimator timer = ValueAnimator.ofInt(secondsToRun);
timer.setDuration(secondsToRun * 1000).setInterpolator(new LinearInterpolator());
timer.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
    {
        @Override
        public void onAnimationUpdate(ValueAnimator animation)
        {
            int elapsedSeconds = (int) animation.getAnimatedValue();
            int minutes = elapsedSeconds / 60;
            int seconds = elapsedSeconds % 60;

            textView.setText(String.format("%d:%02d", minutes, seconds));
        }
    });
timer.start();

Вот простой надежный способ...

Поместите следующий код в свою активность, и метод tick() будет вызываться каждую секунду в потоке пользовательского интерфейса, пока ваша активность находится в состоянии "возобновлено". Конечно, вы можете изменить метод tick(), чтобы делать то, что вы хотите, или вызываться более или менее часто.

@Override
public void onPause() {
    _handler = null;
    super.onPause();
}

private Handler _handler;

@Override
public void onResume() {
    super.onResume();
    _handler = new Handler();
    Runnable r = new Runnable() {
        public void run() {
            if (_handler == _h0) {
                tick();
                _handler.postDelayed(this, 1000);
            }
        }

        private final Handler _h0 = _handler;
    };
    r.run();
}

private void tick() {
    System.out.println("Tick " + System.currentTimeMillis());
}

Для тех, кто интересуется, код "_h0=_handler" необходим, чтобы избежать одновременного запуска двух таймеров, если ваша активность была приостановлена ​​и возобновлена ​​в течение периода времени.

Для тех, кто не может положиться на Chronometer, я сделал полезный класс из одного из предложений:

public class TimerTextHelper implements Runnable {
   private final Handler handler = new Handler();
   private final TextView textView;
   private volatile long startTime;
   private volatile long elapsedTime;

   public TimerTextHelper(TextView textView) {
       this.textView = textView;
   }

   @Override
   public void run() {
       long millis = System.currentTimeMillis() - startTime;
       int seconds = (int) (millis / 1000);
       int minutes = seconds / 60;
       seconds = seconds % 60;

       textView.setText(String.format("%d:%02d", minutes, seconds));

       if (elapsedTime == -1) {
           handler.postDelayed(this, 500);
       }
   }

   public void start() {
       this.startTime = System.currentTimeMillis();
       this.elapsedTime = -1;
       handler.post(this);
   }

   public void stop() {
       this.elapsedTime = System.currentTimeMillis() - startTime;
       handler.removeCallbacks(this);
   }

   public long getElapsedTime() {
       return elapsedTime;
   }

}

использовать.. просто сделайте:

 TimerTextHelper timerTextHelper = new TimerTextHelper(textView);
 timerTextHelper.start();

.....

 timerTextHelper.stop();
 long elapsedTime = timerTextHelper.getElapsedTime();

Вот решение, которое вам нужно добавить в свой код. И вы можете напрямую добавить представление в свой XML-файл.

      import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;

import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;

public class TimerTextView extends TextView {

    private static final int DEFAULT_INTERVAL = 1000;

    private Timer timer = new Timer();
    private long endTime = 0;
    private long interval = DEFAULT_INTERVAL;
    private boolean isCanceled = false;

    public TimerTextView(Context context) {
        super(context);
    }

    public TimerTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public TimerTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public TimerTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        stopTimer();
    }

    @Override protected void onVisibilityChanged(View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);
        if (VISIBLE == visibility) {
            startTimer();
        } else {
            stopTimer();
        }
    }

    public void setInterval(long interval) {
        if (interval >= 0) {
            this.interval = interval;
            stopTimer();
            startTimer();
        }
    }

    public void setEndTime(long endTime) {
        if (endTime >= 0) {
            this.endTime = endTime;
            stopTimer();
            startTimer();
        }
    }

    private void startTimer() {
        if (endTime == 0) {
            return;
        }
        if (isCanceled) {
            timer = new Timer();
            isCanceled = false;
        }
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override public void run() {
                if (null == getHandler()) {
                    return;
                }
                getHandler().post(new Runnable() {
                    @Override public void run() {
                        setText(getDurationBreakdown(endTime - System.currentTimeMillis()));
                    }
                });
            }
        }, 0, interval);
    }

    private void stopTimer() {
        timer.cancel();
        isCanceled = true;
    }

    private String getDurationBreakdown(long diff) {
        long millis = diff;
        if (millis < 0) {
            return "00:00:00";
        }
        long hours = TimeUnit.MILLISECONDS.toHours(millis);
        millis -= TimeUnit.HOURS.toMillis(hours);
        long minutes = TimeUnit.MILLISECONDS.toMinutes(millis);
        millis -= TimeUnit.MINUTES.toMillis(minutes);
        long seconds = TimeUnit.MILLISECONDS.toSeconds(millis);


        return String.format(Locale.ENGLISH, "%02d:%02d:%02d", hours, minutes, seconds);
        //return "${getWithLeadZero(hours)}:${getWithLeadZero(minutes)}:${getWithLeadZero(seconds)}"
    }
}
      enter code here
Thread th=new Thread(new Runnable() {
        @Override
        public void run() {
            try { for(int i=0;i<5;i++) {
                b1.setText(""+i);
                Thread.sleep(5000);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
       pp();
       
                        }
                    }
                });
            }} catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    th.start();

Если кому-то интересно, я начал играть с созданием стандартного объекта для запуска в потоке пользовательского интерфейса. Кажется, работает нормально. Комментарии приветствуются. Я бы хотел, чтобы это было доступно в дизайнере макетов в качестве компонента для перетаскивания в Activity. Не могу поверить, что такого не существует.

package com.example.util.timer;

import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;

public class ActivityTimer {

    private Activity m_Activity;
    private boolean m_Enabled;
    private Timer m_Timer;
    private long m_Delay;
    private long m_Period;
    private ActivityTimerListener m_Listener;
    private ActivityTimer _self;
    private boolean m_FireOnce;

    public ActivityTimer() {
        m_Delay = 0;
        m_Period = 100;
        m_Listener = null;
        m_FireOnce = false;
        _self = this;
    }

    public boolean isEnabled() {
        return m_Enabled;
    }

    public void setEnabled(boolean enabled) {
        if (m_Enabled == enabled)
            return;

        // Disable any existing timer before we enable a new one
        Disable();

        if (enabled) {
            Enable();
        }
    }

    private void Enable() {
        if (m_Enabled)
            return;

        m_Enabled = true;

        m_Timer = new Timer();
        if (m_FireOnce) {
            m_Timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    OnTick();
                }
            }, m_Delay);
        } else {
            m_Timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    OnTick();
                }
            }, m_Delay, m_Period);
        }
    }

    private void Disable() {
        if (!m_Enabled)
            return;

        m_Enabled = false;

        if (m_Timer == null)
            return;

        m_Timer.cancel();
        m_Timer.purge();
        m_Timer = null;
    }

    private void OnTick() {
        if (m_Activity != null && m_Listener != null) {
            m_Activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    m_Listener.OnTimerTick(m_Activity, _self);
                }
            });
        }
        if (m_FireOnce)
            Disable();
    }

    public long getDelay() {
        return m_Delay;
    }

    public void setDelay(long delay) {
        m_Delay = delay;
    }

    public long getPeriod() {
        return m_Period;
    }

    public void setPeriod(long period) {
        if (m_Period == period)
            return;
        m_Period = period;
    }

    public Activity getActivity() {
        return m_Activity;
    }

    public void setActivity(Activity activity) {
        if (m_Activity == activity)
            return;
        m_Activity = activity;
    }

    public ActivityTimerListener getActionListener() {
        return m_Listener;
    }

    public void setActionListener(ActivityTimerListener listener) {
        m_Listener = listener;
    }

    public void start() {
        if (m_Enabled)
            return;
        Enable();
    }

    public boolean isFireOnlyOnce() {
        return m_FireOnce;
    }

    public void setFireOnlyOnce(boolean fireOnce) {
        m_FireOnce = fireOnce;
    }
}

В действии у меня есть это onStart:

@Override
protected void onStart() {
    super.onStart();

    m_Timer = new ActivityTimer();
    m_Timer.setFireOnlyOnce(true);
    m_Timer.setActivity(this);
    m_Timer.setActionListener(this);
    m_Timer.setDelay(3000);
    m_Timer.start();
}

Я использую такой способ:

String[] array={
       "man","for","think"
}; int j;

затем под onCreate

TextView t = findViewById(R.id.textView);

    new CountDownTimer(5000,1000) {

        @Override
        public void onTick(long millisUntilFinished) {}

        @Override
        public void onFinish() {
            t.setText("I "+array[j] +" You");
            j++;
            if(j== array.length-1) j=0;
            start();
        }
    }.start();

это простой способ решить эту проблему.

Если у вас уже есть дельта время.

public class Timer {
    private float lastFrameChanged;
    private float frameDuration;
    private Runnable r;

    public Timer(float frameDuration, Runnable r) {
        this.frameDuration = frameDuration;
        this.lastFrameChanged = 0;
        this.r = r;
    }

    public void update(float dt) {
        lastFrameChanged += dt;

        if (lastFrameChanged > frameDuration) {
            lastFrameChanged = 0;
            r.run();
        }
    }
}
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;

import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.TextView;
import android.app.Activity;

public class MainActivity extends Activity {

 CheckBox optSingleShot;
 Button btnStart, btnCancel;
 TextView textCounter;

 Timer timer;
 MyTimerTask myTimerTask;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  optSingleShot = (CheckBox)findViewById(R.id.singleshot);
  btnStart = (Button)findViewById(R.id.start);
  btnCancel = (Button)findViewById(R.id.cancel);
  textCounter = (TextView)findViewById(R.id.counter);

  btnStart.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View arg0) {

    if(timer != null){
     timer.cancel();
    }

    //re-schedule timer here
    //otherwise, IllegalStateException of
    //"TimerTask is scheduled already" 
    //will be thrown
    timer = new Timer();
    myTimerTask = new MyTimerTask();

    if(optSingleShot.isChecked()){
     //singleshot delay 1000 ms
     timer.schedule(myTimerTask, 1000);
    }else{
     //delay 1000ms, repeat in 5000ms
     timer.schedule(myTimerTask, 1000, 5000);
    }
   }});

  btnCancel.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View v) {
    if (timer!=null){
     timer.cancel();
     timer = null;
    }
   }
  });

 }

 class MyTimerTask extends TimerTask {

  @Override
  public void run() {
   Calendar calendar = Calendar.getInstance();
   SimpleDateFormat simpleDateFormat = 
     new SimpleDateFormat("dd:MMMM:yyyy HH:mm:ss a");
   final String strDate = simpleDateFormat.format(calendar.getTime());

   runOnUiThread(new Runnable(){

    @Override
    public void run() {
     textCounter.setText(strDate);
    }});
  }

 }

}

.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity" >

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:autoLink="web"
    android:text="http://android-er.blogspot.com/"
    android:textStyle="bold" />
<CheckBox 
    android:id="@+id/singleshot"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Single Shot"/>

Я абстрагирую таймер и выделил его в отдельный класс:

Timer.java

import android.os.Handler;

public class Timer {

    IAction action;
    Handler timerHandler = new Handler();
    int delayMS = 1000;

    public Timer(IAction action, int delayMS) {
        this.action = action;
        this.delayMS = delayMS;
    }

    public Timer(IAction action) {
        this(action, 1000);
    }

    public Timer() {
        this(null);
    }

    Runnable timerRunnable = new Runnable() {

        @Override
        public void run() {
            if (action != null)
                action.Task();
            timerHandler.postDelayed(this, delayMS);
        }
    };

    public void start() {
        timerHandler.postDelayed(timerRunnable, 0);
    }

    public void stop() {
        timerHandler.removeCallbacks(timerRunnable);
    }
}

И извлечь основное действие из Timer классифицироваться как

IAction.java

public interface IAction {
    void Task();
}

И я использовал его вот так:

MainActivity.java

public class MainActivity extends Activity implements IAction{
...
Timer timerClass;
@Override
protected void onCreate(Bundle savedInstanceState) {
        ...
        timerClass = new Timer(this,1000);
        timerClass.start();
        ...
}
...
int i = 1;
@Override
public void Task() {
    runOnUiThread(new Runnable() {

        @Override
        public void run() {
            timer.setText(i + "");
            i++;
        }
    });
}
...
}

Надеюсь, это поможет

Вам необходимо создать поток для обработки цикла обновления и использовать его для обновления текстовой области. Сложность состоит в том, что только основной поток может на самом деле изменять пользовательский интерфейс, поэтому поток цикла обновления должен сигнализировать основному потоку о необходимости обновления. Это делается с помощью обработчика.

Проверьте эту ссылку: http://developer.android.com/guide/topics/ui/dialogs.html Нажмите на раздел под названием "Пример ProgressDialog со вторым потоком". Это пример именно того, что вам нужно сделать, за исключением диалогового окна прогресса вместо текстового поля.

void method(boolean u,int max)
{
    uu=u;
    maxi=max;
    if (uu==true)
    { 
        CountDownTimer uy = new CountDownTimer(maxi, 1000) 
  {
            public void onFinish()
            {
                text.setText("Finish"); 
            }

            @Override
            public void onTick(long l) {
                String currentTimeString=DateFormat.getTimeInstance().format(new Date());
                text.setText(currentTimeString);
            }
        }.start();
    }

    else{text.setText("Stop ");
}
Другие вопросы по тегам