在尝试学习如何创建延迟时,我研究并找到了使用Handler / Runnable / postDelayed的主要答案。
Handler handler=new Handler();
final Runnable r = new Runnable()
{
public void run()
{
delayedMethod();
}
};
handler.postDelayed(r, 1000);
暂时有效,但我已经添加了一些其他内容,现在它们有时会以错误的顺序发生。
这组事件:
paintScreen1()
...
delayedPaintScreen2()
...
paintScreen3()
正在搞砸(有时)并且这样做:
paintScreen1()
...
paintScreen3()
...
delayedPaintScreen2()(最后运行并被paintScreen3的操作弄乱)
似乎没有另一种创建延迟的好方法 - 一种不创建线程的方法。
我尝试过的解决方案是为了确保代码事件以正确的顺序运行:
0将主进程放在一个大的同步块中。
1将synchronized关键字放在主进程中涉及的每个方法的方法名称中。
2仅将synchronized关键字放在Runnable中的方法上。
3取走Handler / Runnable / postdelayed并替换为handler.sendEmptyMessageDelayed(0,1000)
4制作一个Handler实例变量,由每个Handler / Runnable块使用(与Handler handler1,handler2,handler3等相反)
5
Handler handler=new Handler();
final Runnable r = new Runnable()
{
public void run()
{
waitOver = true;
}
};
handler.postDelayed(r, 1000);
while (waitOver == false) {
}
delayedMethod();
waitOver = false;
我的下一次尝试可能是尝试以某种方式使用Thread类,因此我可以调用thread.join()。 如果失败了,我担心接下来的事情将会非常漫长和复杂。
有什么建议吗?
解决方案的任何简单示例?
由于
编辑:我可能会对Handler / Runnable是否导致文字线程感到困惑。
编辑:这是一场游戏。用户进行移动,屏幕更新以显示移动,计算表明他们得分,重新着色屏幕上的框,添加延迟以允许用户查看他们的点,然后调用方法去除彩色方块,当该方法完成时我们返回到调用它的方法(包含Handler / runnable),代码继续向下调用另一个方法,导致板的随机方块变为紫色。所以它应该发生用户移动,重绘显示点得分,延迟使用户可以看到得分,重绘擦除方块,然后随机紫色方块发生。有时会发生什么(据我所知)是随机的紫色方块将在它应该执行之前执行,选择其中一个点得分,干扰,并使其清理方法变得困惑并且无法清理。
mainmethod(){
...
if(pointscored){
squaresglow();
...
//延迟,以便用户可以在清理发生之前看到发光
处理器可运行
清理();
postdelayed
}
...
purpleSquare();
}
我希望这不会让人感到困惑。 purpleSquare在清理之前运行,事情搞砸了。
编辑: 试过这个: 6
CountDownLatch doneSignal = new CountDownLatch(1);
Handler handler=new Handler();
final LatchedRunnable lr = new LatchedRunnable(doneSignal);
handler.postDelayed(lr, COMPUTER_MOVE_DELAY);
try {
doneSignal.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
class LatchedRunnable implements Runnable {
private final CountDownLatch doneSignal;
LatchedRunnable(CountDownLatch doneSignal) {
this.doneSignal = doneSignal;
}
public void run() {
delayedProcess();
doneSignal.countDown();
}
}
7
ExecutorService executorService = Executors.newFixedThreadPool(5);
final CountDownLatch latch = new CountDownLatch(1);
executorService.execute(new Runnable() {
public void run() {
try {
Looper.prepare();
Handler handler=new Handler();
final Runnable r = new Runnable()
{
public void run()
{
delayedMethodCleanupCalc();
}
};
handler.postDelayed(r, 4000);
} finally {
latch.countDown();
}
}
});
try {
latch.await();
delayedMethodPaintScreen();
} catch (InterruptedException e) {
// todo >> handle exception
}
答案 0 :(得分:1)
purpleSquare在清理之前运行,事情搞砸了
mainmethod() { ... if (pointscored) { squaresglow(); ... //delay so user can see the glow before the cleanup happens Handler-runnable cleanup(); postdelayed } ... purpleSquare(); }
你有一个设计缺陷。将Handler视为将执行代码的消息队列"稍后"每当处理器决定处理消息并postDelayed作为在队列底部填充该消息的不精确方法。如果你调用postDelayed并且你仍然要在当前方法中保留代码行来执行,那么在偶然接收到postDelayed消息之前这些行很可能会执行。
你要做的是确保在点计算例程完成它之后调用purpleSquare(),这可能需要等待它完成。在这种情况下,PostDelaying到消息队列不是您应该做的。你应该使用的是信号量和pointScored线程。
考虑以下代码设计:
final Runnable pointScoredTask = new Runnable() {
public synchronized void run() {
try {
squaresglow();
//...
Thread.sleep(2500); //2.5 sec before cleanup occurs
cleanup();
} catch (InterruptedException e) {
}
notify(); //make sure we call notify even if interrupted
}
};
void mainmethod() {
//...
if (bPointWasScored) {
synchronized (pointScoredTask) {
try {
Thread psThread = new Thread(pointScoredTask,"pointscored");
psThread.start(); //thread will start to call run(), but we get control back to avoid race condition
pointScoredTask.wait(6000); //wait no more than 6 sec for the notify() call
} catch (InterruptedException e) {
}
}
//if a point was scored, nothing past this line will execute until scoreglow has been cleaned up
}
//...
purpleSquare();
//...
}
我知道你宁愿避免使用线程,但有一些东西在使用它们时效果会更好。尝试上面的设计,看看是否能解决您遇到的同步问题。