Как запустить поток Runnable в Android через определенные промежутки времени?
Я разработал приложение для отображения некоторого текста через определенные промежутки времени на экране эмулятора Android. Я использую класс Handler
. Вот фрагмент моего кода:
handler = new Handler();
Runnable r = new Runnable() {
public void run() {
tv.append("Hello World");
}
};
handler.postDelayed(r, 1000);
Когда я запускаю это приложение, текст отображается только один раз. Почему?
Ответы
Ответ 1
Простое решение для вашего примера:
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
Ответ 2
new Handler().postDelayed(new Runnable() {
public void run() {
// do something...
}
}, 100);
Ответ 3
Я думаю, что может улучшить первое решение Alex2k8 для обновления, исправляющего каждую секунду
1. Исходный код:
public void run() {
tv.append("Hello World");
handler.postDelayed(this, 1000);
}
2. Анализ
- В приведенной выше стоимости предположим
tv.append("Hello Word")
стоимость T миллисекунды, после отображения 500 время с задержкой 500 * T миллисекунды
- Он будет увеличиваться с задержкой при длительном прогоне
3. Решение
Чтобы избежать этого Просто измените порядок postDelayed(), чтобы избежать задержки:
public void run() {
handler.postDelayed(this, 1000);
tv.append("Hello World");
}
Ответ 4
Для повторной задачи вы можете использовать
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 runnable = new Runnable()
{
@Override
public void run()
{
}
};
И назовите это двумя способами
new Handler().postDelayed(runnable, 500 );//where 500 is delayMillis // to work on mainThread
ИЛИ
new Thread(runnable).start();//to work in Background
Ответ 5
Я считаю, что для этого типичного случая, то есть для запуска чего-то с фиксированным интервалом, 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 не равен null)
Ответ 6
Handler handler=new Handler();
Runnable r = new Runnable(){
public void run() {
tv.append("Hello World");
handler.postDelayed(r, 1000);
}
};
handler.post(r);
Ответ 7
Если я правильно понимаю документацию метода Handler.post():
Заставляет Runnable r добавляться в очередь сообщений. Runnable будет запущен в потоке, к которому прикреплен этот обработчик.
Таким образом, примеры, предоставленные @alex2k8, хотя и работают правильно, не совпадают.
В случае, если используется Handler.post()
, не создаются новые потоки. Вы просто отправляете Runnable
в поток с Handler
, который будет выполняться EDT.
После этого EDT выполняет только Runnable.run()
, ничего больше.
Помните:
Runnable != Thread
.
Ответ 8
Интересным примером является то, что вы можете постоянно видеть, как счетчик/секундомер работает в отдельном потоке. Также показано 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 и текущее время, выполняемое вместе с потоком пользовательского интерфейса основной активности
Ответ 9
Если вы хотите быть уверенным, что Handler будет прикреплен к основному потоку, вы должны инициализировать его следующим образом:
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
public void run() {
// do something...
}
}, 100);
Ответ 10
теперь в 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
}
Ответ 11
Котлин
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)
}
Джава
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);
}