2014-07-04 47 views
0

我以編程方式創建一些視覺事件,即當您單擊按鈕時使圖像出現,它應該等待500ms,然後將圖像從屏幕上掃過一個滑動效果。但是,如果我嘗試使用Thread.sleep,它在進入睡眠狀態之前不會處理先前的UI事件,因此在這種情況下,應該將圖像設置爲可見,然後它會休眠,但會在圖像可見之前休眠。此外,移動視圖的循環太快 - 我希望使用Thread.sleep稍微減慢它,但看起來像不起作用。在Android應用程序中非冷凍睡眠

什麼是更好的方法來做到這一點?

View passImage = frontView.findViewWithTag(SearchConstants.PassImageTag); 
passImage.setAlpha((float) 1); 
frontView.setRotation((float)-10); 

try { 
    Thread.sleep(1000); 
} catch (InterruptedException e) { 
    e.printStackTrace(); 
} 

for (float i = 0; i > 0 - halfScreenWidth; i--) { 
    frontView.setX(i); 
} 
+1

'的Thread.sleep()'在這種情況下將發出'主事件處理UI thread'睡覺,所以應用程序完全凍結。使用某種類型的Timer,如CountDownTimer。 – EpicPandaForce

+0

或postDelayed與處理程序 –

回答

3

NEVER使用Thread.sleep()。如果你這樣做,你會阻止當前Thread。這意味着,如果您要在UI Thread上調用Thread.sleep(),則界面會凍結,您無法再與其進行交互,就像您遇到過的情況一樣。有多種選擇來安排未來的任務或事件。您可以:

  1. 使用Timer
  2. 使用HandlerpostDelayed()
  3. 使用AlarmManager

使用Timer

Timer可用於安排TimerTask。他們最適合安排幾秒鐘的任務,也許幾分鐘到將來。

首先你必須寫一個TimerTask。該任務將在一段時間後執行。一個TimerTask可能是這樣的:

private class ExampleTask extends TimerTask { 

    @Override 
    public void run() { 
     // This method is called once the time is elapsed 
    } 
} 

而且你可以安排TimerTask這樣的:

Timer timer = new Timer(); 
ExampleTask task = new ExampleTask(); 

// Executes the task in 500 milliseconds 
timer.schedule(task, 500); 

使用HandlerpostDelayed()

使用Handler是非常類似於使用一個Timer,但我個人更喜歡使用Timer因爲他們更適合這樣的工作。 Handler原本是爲了方便Threads和其他事情之間的溝通,但它們也可以用於安排Runnable。首先,我們必須定義一個Runnable,這是非常類似TimerTask

Runnable runnable = new Runnable() { 

    @Override 
    public void run() { 
     // This method will be executed in the future 
    } 
}; 

現在,我們安排Runnable在未來postDelayed()執行:

Handler handler = new Handler(); 

// Execute the Runnable in 500 milliseconds 
handler.postDelayed(runnable, 500); 

使用AlarmManager

AlarmManager是一個系統服務,可用於發送一個Intent在未來的某個時刻。您可以使用AlarmManager將此Intent安排在未來數月甚至數年,唯一的缺點是您必須在重新啓動電話時重置所有警報。

你可以得到AlarmManager這樣的:

AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 

您還需要包裹Intent要在PendingIntent派:

Intent intent = new Intent(SOME_ACTION); 
... // Setup your intent 
PendingIntent pendingIntent = PendingIntent.getService(context, REQUEST_CODE, intent, PendingIntent.FLAG_CANCEL_CURRENT); 

而且你可以安排Intent發送在特定的Date這樣的:

manager.set(AlarmManager.RTC, date.getTime(), pendingIntent); 
+0

我已經走了計時器的方法,但問題是TimerTask在不同的線程上執行,它必須移動視圖的X位置 - 我得到例外07-04 10:28:43.710 :E/AndroidRuntime(1630):android.view.ViewRootImpl $ CalledFromWrongThreadException:只有創建視圖層次結構的原始線程可以觸及其視圖。 – NZJames

+0

哦,在這種情況下,我建議你使用'Runnable'而不是'TimerTask'並調用'view.postDelayed(runnable,500);'。這將'Runnable'延遲500毫秒發佈到正確的線程,以便您可以與'View'進行交互。 –

+0

您的問題解決了還是仍然有問題? –

0

你也可以使用一個AsyncTask

class ShowImageTask extends AsyncTask<Void, Void, Void> { 

    @Override 
    protected Integer doInBackground(Void... args) { 
    Thread.sleep(500); 
    showImage(); 
    } 

} 

void someMethod(){ 
    new ShowImageTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 
} 
+1

這真是一個可怕的解決方案...... –

+0

請詳細說明......據我所知,上面顯示的所有場景都包含線程創建,其開銷較多或較少。爲什麼'AsyncTask'很糟糕? TIA – injecteer

+0

您正在創建一個新的'Thread'並立即將其封鎖。它基本上什麼都不做,但是你同時也阻止了'AsyncTask'的執行者。所以沒有其他的'AsyncTasks'可以運行,而這個本質上什麼都不做。您可以將執行程序設置爲並行執行,但可能會導致嚴重的後果,例如競爭狀況,加載時間過長和性能低下,這就是爲什麼串行執行是默認設置。另外創建一個'AsyncTask'並不是那麼便宜。如果任務本身沒有做任何事情,那麼所有這些開銷真的不值得。 –