如何在Android中以定义的时间间隔运行Runnable线程?

时间:2009-12-17 12:42:03

标签: android multithreading

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

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

当我运行此应用程序时,文本仅显示一次。为什么呢?

11 个答案:

答案 0 :(得分:498)

您示例的简单修复是:

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

您可以将runnable对象视为可以发送到消息队列以执行的命令,并将handler作为用于发送该命令的辅助对象。

详情请见http://developer.android.com/reference/android/os/Handler.html

答案 1 :(得分:40)

我认为可以改进Alex2k8的第一个解决方案,以便每秒更新一次

1.原始代码:

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

<强> 2.Analysis

  • 在上述费用中,假设tv.append("Hello Word")费用 T 毫秒,显示 500 次延迟时间 500 * T 毫秒< / LI>
  • 长时间运行会延迟

第3。溶液

要避免只改变postDelayed()的顺序,以避免延迟:

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

答案 2 :(得分:39)

new Handler().postDelayed(new Runnable() {
    public void run() {
        // do something...              
    }
}, 100);

答案 3 :(得分:23)

我相信这种典型情况,即以固定间隔运行某些东西,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不为空)

答案 4 :(得分:23)

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

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 

答案 5 :(得分:16)

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

答案 6 :(得分:3)

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

  

使Runnable r添加到消息队列中。 runnable将在连接此处理程序的线程上运行。

所以@ alex2k8提供的例子即使工作正常也不一样。 如果使用Handler.post()不会创建新线程。您只需将Runnable发布到Handler的帖子即EDT执行。 之后,EDT仅执行Runnable.run(),而不执行任何其他操作。

记住: Runnable != Thread

答案 7 :(得分:1)

一个有趣的例子是你可以在不同的线程中连续看到一个计数器/秒表运行。还显示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();
}

要查看代码,请参阅此处:

Thread example displaying GPS Location and Current Time runnable alongside main-activity's User Interface Thread

答案 8 :(得分:1)

Kotlin与协程

在Kotlin中,可以使用协同程序执行以下操作:

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

尝试here

答案 9 :(得分:0)

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

答案 10 :(得分:0)

科特林

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