如何运行一个可运行的线程在Android在定义的间隔?

我开发了一个应用程序,在Android模拟器屏幕上以指定的间隔显示一些文本。我正在使用Handler类。下面是我的代码片段:

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

当我运行这个应用程序时,文本只显示一次。为什么?

716826 次浏览

对你的例子的简单修复是:

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

我认为可以改进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");
}
Handler handler=new Handler();
Runnable r = new Runnable(){
public void run() {
tv.append("Hello World");
handler.postDelayed(r, 1000);
}
};
handler.post(r);

如果我正确理解Handler.post()方法的文档:

导致Runnable r被添加到消息队列。可运行对象将在附加此处理程序的线程上运行。

所以@alex2k8提供的例子,即使工作正确,也是不一样的。 如果使用Handler.post(),则没有新的线程被创建. c。你只需要将Runnable传递给带有Handler的线程,由美国东部时间执行。 在此之后,EDT只执行Runnable.run(),不执行其他任何操作 < p >记住: Runnable != Thread . < / p >

我相信对于这种典型的情况,即运行具有固定间隔的东西,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不为空)
new Handler().postDelayed(new Runnable() {
public void run() {
// do something...
}
}, 100);

对于重复任务,您可以使用

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

new Thread(runnable).start();//to work in Background

一个有趣的例子是,你可以连续看到一个计数器/秒表在不同的线程中运行。还显示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位置和当前时间可与main-activity的用户界面线程一起运行

现在在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
}

芬兰湾的科特林

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);
}

带有协程的Kotlin

在Kotlin中,使用协程你可以做以下事情:

CoroutineScope(Dispatchers.Main).launch { // Main, because UI is changed
ticker(delayMillis = 1000, initialDelayMillis = 1000).consumeEach {
tv.append("Hello World")
}
}

试试在这里!