在触摸事件期间从后台线程更新UI

时间:2012-03-18 18:13:46

标签: android android-mapview handler

我正在尝试从后台线程向MapView添加叠加层,以光学标记用户当前正在触摸的点。

目前我尝试使用Timer / Handler实现这一目标。 当MotionEvent是ACTION_DOWN时,我发布一个任务,在一定的延迟后将圆形叠加添加到mapView叠加层。

不幸的是,只有在用户从屏幕上移开手指后才会更新UI(ACTION_UP)。

以下是示例代码:

UI主题

if (event.getAction() == MotionEvent.ACTION_DOWN) {
    handler = new OverlayHandler(mapView, centerDrawer) // centerDrawer is an overlay drawing a circle
    cTask = new DrawTimer(handler); // Calls handler.sendMessage, telling the handler to add centerDraw to the overlays of mapView

    handler.postDelayed(cTast, delay);

} else {
    handler.removeCallbacks(cTask);
}

计时器(DrawTimer等)

public void run() {
    Message msg = new Message();
    msg.what = 1;
    handler.sendMessage(msg);
}

处理程序

public void handleMessage(Message msg) {
    switch (msg.what) {
    case 1:
            mapView.getOverlays().add(centerDrawer);
    break;
        // more cases
    }
    super.handleMessage(msg);
}

据我所知,这是从后台任务与UI交互的默认方式。

当用户与屏幕交互时,这对于更新是否也有效? 我是否必须明确告诉视图呈现新的叠加层?

修改

代码应该执行以下操作: 在触摸时,应该开始观察用户持续触摸的时间。在初始延迟之后,应将圆圈添加到视图中。经过一段时间的延迟后,会添加另一个叠加层等等。

我分两步完成每个叠加: 我将一个Runnable添加到处理程序中,以便在延迟后执行。 Runnable然后将相应的消息发送给处理程序,告诉它,绘制什么。 我这样做,因为......

  • 如果用户移动或松开手指,我需要能够取消定时器(帖子)。
  • 当用户一直触摸屏幕时,某些叠加层应该更改。 postDelayed Runnable只是一直发送消息直到取消。

这就是为什么我不只是使用延迟信息。

使用案例

  • 用户触摸屏幕 - >用户在延迟通过之前释放(不应出现任何内容)

  • 触摸 - >延迟通过 - >圈子 - >释放

  • 触摸 - >延迟通过 - >圈子 - >延迟2次通过 - >圈2 - >释放

2 个答案:

答案 0 :(得分:2)

您的评论说“调用handler.sendMessage ...”,但随后您将延迟发布到处理程序。你要么想要调用sendMessage,要么调用postDelayed,而不是两者。你把消息放在队列2x上。但这并不一定能解释你的问题。

你应该发布DelayTimer的代码,并检查延迟的值。

答案 1 :(得分:0)

在这个问题中找到答案: Views Don't Update Until MapView is Touched

mapView.invalidate()强制视图重绘其所有叠加层。它可能不是实现该行为的最有效方式,但它以我想要的方式工作。

感谢farble1670指出我之前实现的一些问题。 根据他的建议,我将其更改为仅使用消息(使用removeMessage也可以取消)。

新代码更简单:

用户界限线程

if (event.getAction() == MotionEvent.ACTION_DOWN) {
    handler = new OverlayHandler(mapView, centerDrawer)

    handler.sendEmptyMessageDelayed(1, d);

} else {
    handler.removeMessage(1);
}

<强>处理程序

public void handleMessage(Message msg) {
    switch (msg.what) {
    case 1:
        mapView.getOverlays().add(centerDrawer);
    break;
        // more cases
    }
    mapView.invalidate(); // Forces redrawing of all overlays
    super.handleMessage(msg);
}