Как запустить поток Runnable в Android через определенные промежутки времени? - PullRequest
322 голосов
/ 17 декабря 2009

Я разработал приложение для отображения некоторого текста через определенные интервалы на экране эмулятора Android. Я использую класс Handler. Вот фрагмент из моего кода:

handler = new Handler();
Runnable r = new Runnable() {
    public void run() {
        tv.append("Hello World");               
    }
};
handler.postDelayed(r, 1000);

Когда я запускаю это приложение, текст отображается только один раз. Почему?

Ответы [ 10 ]

500 голосов
/ 17 декабря 2009

Простое исправление для вашего примера:

handler = new Handler();

final Runnable r = new Runnable() {
    public void run() {
        tv.append("Hello World");
        handler.postDelayed(this, 1000);
    }
};

handler.postDelayed(r, 1000);

Или мы можем использовать нормальную нить, например (с оригинальным Runner):

Thread thread = new Thread() {
    @Override
    public void run() {
        try {
            while(true) {
                sleep(1000);
                handler.post(this);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
};

thread.start();

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

Подробнее здесь http://developer.android.com/reference/android/os/Handler.html

40 голосов
/ 23 июля 2011

Я думаю, что можно улучшить первое решение Alex2k8 для правильного обновления каждую секунду

1. Оригинальный код:

public void run() {
    tv.append("Hello World");
    handler.postDelayed(this, 1000);
}

* 1009 2. Анализ *

  • В приведенной выше стоимости предположим, что tv.append("Hello Word") стоимость T миллисекунд, после отображения 500 время задержки составляет 500 * T миллисекунд
  • Увеличивается с задержкой при длительном запуске

3. Решение

Чтобы избежать этого, просто измените порядок postDelayed (), чтобы избежать задержки:

public void run() {
    handler.postDelayed(this, 1000);
    tv.append("Hello World");
}
39 голосов
/ 21 июля 2014
new Handler().postDelayed(new Runnable() {
    public void run() {
        // do something...              
    }
}, 100);
23 голосов
/ 28 апреля 2015

Для повторения задания вы можете использовать

new Timer().scheduleAtFixedRate(task, runAfterADelayForFirstTime, repeaingTimeInterval);

Назовите это как

new Timer().scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {

            }
        },500,1000);

Приведенный выше код будет запускаться впервые после полсекунды (500) и повторяться после каждой секунды (1000)

Где

задача - метод для выполнения

после времени до первоначального исполнения

( интервал время повторения исполнения)

Во-вторых

И вы также можете использовать CountDownTimer , если хотите выполнить задачу несколько раз.

    new CountDownTimer(40000, 1000) { //40000 milli seconds is total time, 1000 milli seconds is time interval

     public void onTick(long millisUntilFinished) {
      }
      public void onFinish() {
     }
    }.start();

//Above codes run 40 times after each second

И вы также можете сделать это с помощью runnable. создать работоспособный метод, такой как

Runnable runnable = new Runnable()
    {
        @Override
        public void run()
        {

        }
    };

И назовите это обоими этими способами

new Handler().postDelayed(runnable, 500 );//where 500 is delayMillis  // to work on mainThread

OR

new Thread(runnable).start();//to work in Background 
23 голосов
/ 30 декабря 2012

Я считаю, что для этого типичного случая, то есть для запуска чего-либо с фиксированным интервалом, Timer более уместно. Вот простой пример:

myTimer = new Timer();
myTimer.schedule(new TimerTask() {          
@Override
public void run() {
    // If you want to modify a view in your Activity
    MyActivity.this.runOnUiThread(new Runnable()
        public void run(){
            tv.append("Hello World");
        });
    }
}, 1000, 1000); // initial delay 1 second, interval 1 second

Использование Timer имеет несколько преимуществ:

  • Начальную задержку и интервал можно легко указать в аргументах функции schedule
  • Таймер можно остановить, просто позвонив myTimer.cancel()
  • Если вы хотите, чтобы был запущен только один поток, не забудьте вызвать myTimer.cancel() до планирования нового (если myTimer не ноль)
16 голосов
/ 03 мая 2012
Handler handler=new Handler();
Runnable r = new Runnable(){
    public void run() {
        tv.append("Hello World");                       
        handler.postDelayed(r, 1000);
    }
}; 
handler.post(r);
3 голосов
/ 09 октября 2012

Если я правильно понимаю документацию метода Handler.post ():

Заставляет Runnable r быть добавленным в очередь сообщений. Runnable будет запущен в потоке, к которому подключен этот обработчик.

Таким образом, примеры, предоставленные @ alex2k8, хотя и работают правильно, но не совпадают. В случае использования Handler.post(), новые темы не создаются . Вы просто публикуете Runnable в ветке с Handler для исполнения EDT После этого EDT выполняет только Runnable.run(), ничего больше.

Помните: Runnable != Thread.

1 голос
/ 25 августа 2017

Интересным примером является то, что вы можете постоянно видеть счетчик / секундомер, работающий в отдельном потоке. Также показывает GPS-местоположение. В то время как основной вид деятельности Тема интерфейса пользователя уже существует.

Выдержка:

try {    
    cnt++; scnt++;
    now=System.currentTimeMillis();
    r=rand.nextInt(6); r++;    
    loc=lm.getLastKnownLocation(best);    

    if(loc!=null) { 
        lat=loc.getLatitude();
        lng=loc.getLongitude(); 
    }    

    Thread.sleep(100); 
    handler.sendMessage(handler.obtainMessage());
} catch (InterruptedException e) {   
    Toast.makeText(this, "Error="+e.toString(), Toast.LENGTH_LONG).show();
}

Чтобы посмотреть код смотрите здесь:

Пример потока, показывающий местоположение GPS и текущее время, работающее вместе с темой пользовательского интерфейса основной деятельности

0 голосов
/ 21 сентября 2018

Котлин

private lateinit var runnable: Runnable
override fun onCreate(savedInstanceState: Bundle?) {
    val handler = Handler()
    runnable = Runnable {
        // do your work
        handler.postDelayed(runnable, 2000)
    }
    handler.postDelayed(runnable, 2000)
}

Java

Runnable runnable;
Handler handler;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    handler = new Handler();
    runnable = new Runnable() {
        @Override
        public void run() {
            // do your work
            handler.postDelayed(this, 1000);
        }
    };
    handler.postDelayed(runnable, 1000);
}
0 голосов
/ 25 июля 2018

теперь в Kotlin вы можете запускать потоки следующим образом:

class SimpleRunnable: Runnable {
    public override fun run() {
        println("${Thread.currentThread()} has run.")
    }
}
fun main(args: Array<String>) {
    val thread = SimpleThread()
    thread.start() // Will output: Thread[Thread-0,5,main] has run.
    val runnable = SimpleRunnable()
    val thread1 = Thread(runnable)
    thread1.start() // Will output: Thread[Thread-1,5,main] has run
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...