2012-03-18 64 views
2

我试图从后台线程向MapView添加一个叠加层以光学标记用户当前正在触摸的点。在触摸事件期间从后台线程更新UI

目前我尝试使用定时器/处理程序实现该功能。 当MotionEvent为ACTION_DOWN时,我发布了一个任务,它在一定的延迟之后将圆形覆盖图添加到mapView覆盖图。

不幸的是,用户界面仅在用户从屏幕上移除手指(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 - >发布

回答

0

发现在这个问题的答案: Views Don't Update Until MapView is Touched

mapView.invalidate()强制重绘其所有叠加的视图。它可能不是实现这种行为的最有效的方式,但它按我希望的方式工作。

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

新的代码更简单:

UI线程

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

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

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

+0

可运行在postDelayed添加的延迟后执行。然后(延迟之后)告诉Handler更新UI。我不会在队列中发布两次相同的信息。 我需要这样做,因为如果用户在延迟过去之前移开手指,我需要能够取消绘图。 我用这个信息澄清我的问题。 – PvB 2012-03-18 19:13:50

+0

postDelayed()不是一个确切的计时器。 UI消息队列处理事情,因为它有时间这样做,所以有可能例如您的两条消息几乎同时被处理。我不能说这是你的问题的原因,但它可能是你的代码中的问题。您是否添加了日志语句以查看您何时正在获取ACTION_UP和ACTION_DOWN事件? – 2012-03-18 19:29:28

+0

好吧,有趣的是,如果我使用sendMessageAtTime,则会在触摸时出现圆。你可能是对的,Runnables有问题。我深入了解它,感谢您指出这一点! – PvB 2012-03-18 19:32:25