2012-03-18 102 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