来自Handler的Android更新UI

时间:2013-07-11 14:18:46

标签: android handler runnable

我知道,在stackoverflow和网上的其他地方有很多这样的问题,但在我读了很多这些,以及官方的android处理程序文档后,我真的不明白它是如何工作的

游戏的概念是,玩家应该猜出一个数字。

我想做什么? 我有4名球员,3名是机器人,1名是人(我)。 我在UI上制作了4个插槽(只是视图),并将图像和文本视图放入其中。

目标是迭代4个玩家,如果是机器人,那么稍等一下(随机),更新其插槽文本,然​​后跳转到下一个玩家。

如果是人类,请显示一些按钮,等待玩家按下按钮,然后隐藏按钮。

如果人类之后有更多的机器人玩家,那么就按照我上面描述的关于机器人做的事情。

好的,我有一个代码,它似乎有效,特别是当我处于调试模式时,但是当我在手机上运行时,有时会发生事情,应该在它应该之前。

例如,玩家的顺序是: Robot 1,Robot2,Human,Robot3。

机器人1正在更新它的文本,但由于某种原因机器人2没有,人类来了,等我按下按钮,机器人3也更新。

当我尝试记录而不是调试时,我看到,该程序完全混乱。

好的,所以代码: 我有一个可运行的引擎,实现了runnable:

 ...
 public abstract void update();

@Override
public void run() {
    // TODO Auto-generated method stub
    while (isRunning) {
        if (!isComplete) {
            update();
        }
        isComplete = true;
    }

}
...

这是活动,扩展了上面的代码。

    private Handler messageHandler = new Handler() {

    public void handleMessage(Message msg) {
        // update your view here
        if (msg.what == ROBOT_GUESS) {
            activeSlot.setSlotGuess();
            Log.d(LOG_TAG, "Robot update: " + activeSlot.getPlayerId());
        } else if (msg.what == HUMAN_GUESS) {
            buttonsContainer.setVisibility(View.VISIBLE);
            Log.d(LOG_TAG, "Human buttons");
        } else if (msg.what == HUMAN_HAS_GUESSED) {
            buttonsContainer.setVisibility(View.GONE);
            activeSlot.setSlotGuess();
            Log.d(LOG_TAG, "Human buttons removed");
        }
    }
};

private OnClickListener playerGuessClickListener = new OnClickListener() {
    public void onClick(View v) {
        Toast.makeText(getApplicationContext(), "Your guess: " + v.getId(), Toast.LENGTH_LONG).show();
        activeSlot.getPlayer().setGuess(v.getId());
        isPlayerGuessed = true;
    }
};

@Override
public void update() {
    // TODO Auto-generated method stub
    Log.d(LOG_TAG, "Update");

    for (Slot slot : slots) {
        SnobliPlayer player = slot.getPlayer();
        if (player.getType() != PlayerTypes.HUMAN.getTypeValue()) {
            Log.d(LOG_TAG, "This is a robot");
            // This player doesn't hide yet. He should hide.
            // And it should be a Robot player
            player.guess();
            try {
                // Waiting some time between 1 - 3 second.
                Random random = new Random();
                Thread.sleep(random.nextInt(2000) + 1000);
                Log.d("UPDATE", String.valueOf("ROBOT GUESS"));
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            activeSlot = slot;
            messageHandler.sendEmptyMessage(ROBOT_GUESS);

        } else {
            // Now the human player comes.
            Log.d(LOG_TAG, "I am the player");
            activeSlot = slot;
            messageHandler.sendEmptyMessage(HUMAN_GUESS);
            while (!isPlayerGuessed) {
                // Do nothing
            }
            messageHandler.sendEmptyMessage(HUMAN_HAS_GUESSED);

        }

    }

}

为什么会发生这种情况,我怎么能这样做,玩家会等待对方的猜测?

谢谢。

1 个答案:

答案 0 :(得分:0)

我认为你在这里有一个线程问题......

  

例如,玩家的顺序是:Robot 1,Robot2,Human,Robot3

你说Robot2被跳过了。这是因为update方法中的for循环不会等待处理程序完成执行,因为它们位于不同的线程上。在Robot2移动之后,人类转向接下来你打电话

activeSlot = slot;
messageHandler.sendEmptyMessage(HUMAN_GUESS);

问题是......您不确定处理程序是否已调用

activeSlot.setSlotGuess();

最后一次机器人的猜测..所以当轮到人的时候,人类设置了activeSlot,你不知道Robot2是否有机会设定它的猜测。最好等到转弯,直到使用activeSlot对象完成处理程序。

你可以这样做..

for (Slot slot : slots) {

     // at the end of your for loop..
     synchronized (activeSlot) {
         activeSlot.wait();
     }

}

然后在你的处理程序中的if语句之后......

synchronized (activeSlot) {
    activeSlot.notify();
}

这将确保在下一回合再次设置处理程序之前使用activeSlot对象完成处理程序。