如何在Android中以定义的间隔运行一个Runnable线程?
我开发了一个应用程序,以在Android模拟器屏幕中以定义的间隔显示一些文本。 我正在使用Handler
类。 这里是我的代码片段:
handler = new Handler(); Runnable r = new Runnable() { public void run() { tv.append("Hello World"); } }; handler.postDelayed(r, 1000);
当我运行这个应用程序时,文本只显示一次。 为什么?
你的例子的简单修复是:
handler = new Handler(); final Runnable r = new Runnable() { public void run() { tv.append("Hello World"); handler.postDelayed(this, 1000); } }; handler.postDelayed(r, 1000);
或者我们可以使用正常的线程(例如原始亚军):
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的第一个解决scheme,每秒更新一次
1.原代码:
public void run() { tv.append("Hello World"); handler.postDelayed(this, 1000); }
2.Analysis
- 在以上成本中,假设
tv.append("Hello Word")
花费T毫秒,显示500次后延迟时间为500 * T毫秒 - 运行时间过长会延迟
3.解决scheme
为了避免这种情况,只要改变postDelayed()的顺序,避免延迟:
public void run() { handler.postDelayed(this, 1000); tv.append("Hello World"); }
new Handler().postDelayed(new Runnable() { public void run() { // do something... } }, 100);
我相信对于这个典型的情况,即运行一个固定的时间间隔, 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)
重复你可以使用的任务
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来完成。 创build一个可运行的方法
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
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被添加到消息队列中。 runnable将在该处理程序所连接的线程上运行。
所以@ alex2k8提供的例子,即使正常工作,是不一样的。 如果使用Handler.post()
,则不会创build新的线程 。 您只需将Runnable
发布到Handler
的线程以由EDT执行。 之后,EDT只执行Runnable.run()
,没有别的。
记住: Runnable != Thread
。
一个有趣的例子是你可以连续看到一个计数器/秒表在单独的线程运行。 还显示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位置和当前时间的主题示例可与主活动的用户界面线程一起运行
如果你想确保Handler将被附加到主线程,你应该像这样初始化它:
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { public void run() { // do something... } }, 100);