2014-01-15 94 views
0

所以在下面發佈的代碼中,我有一個迭代10次的for循環,for循環的目標是每0.5秒創建10次相同的ImageView。當我測試它時,它會在5秒後同時添加所有內容(假設它是通過循環並等待500ms再次通過,500ms * 10 = 5秒)。for循環中的Thread.sleep導致循環體的問題

問題是,爲什麼它會在循環中等待500ms 10次然後執行for循環中的所有內容。

我添加了Log.i打印消息,看看是否會同時打印,並且如果我的線程或for循環出現問題,並且消息每500ms打印一次。我不明白爲什麼它每500毫秒執行一次Log.i消息,但循環內的其餘代碼是在位於相同括號內並且都在Thread.sleep方法之前完成的。

謝謝! 代碼: 主代碼(該錯誤是btnRoundsClick方法內)

Variables var = new Variables(); 
EntityActions e = new EntityActions(); 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    requestWindowFeature(Window.FEATURE_NO_TITLE); 
    final Window window = getWindow(); 
    window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,    WindowManager.LayoutParams.FLAG_FULLSCREEN); 
    setContentView(R.layout.firstmap); 
    FontTextView username = (FontTextView) findViewById(R.id.lblUsername); 
    username.setText("NAME"); 
    RelativeLayout map1 = (RelativeLayout) findViewById(R.id.map1); 
    e.setMap(map1); 
} 

// On click of button, add enemies 
public void btnRoundsClick(View view) { 
    ImageView firetower[] = new ImageView[10]; 
    for (int c = 0; c < 10; c++) { 
     try 
       { 
       firetower[c] = new ImageView(Start.this); 
        firetower[c].setImageResource(R.drawable.firetower); 
       e.setEnemy(firetower[c]); 
       e.setStartEnd(0, 0, 0, 198); 
       e.addEnemy(); 
       e.followPath(); 
       Log.i("There is 1 ", "more ImageView"); 
       Thread.sleep(500); 
      } catch (Exception e) 
      { 
       e.printStackTrace(); 
      } 
    } 
} 

EntityActions類 ImageView的敵人; int startX,startY,endX,endY; RelativeLayout map;

public EntityActions() { 
    startX = 0; 
    endX = 0; 
    startY = 0; 
    endY = 0; 
} 

public void setEnemy(ImageView enem) { 
    enemy = enem; 
} 

public void setMap(RelativeLayout m) { 
    map = m; 
} 

public void addEnemy() { 
    map.addView(enemy); 
    enemy.getLayoutParams().height = 60; 
    enemy.getLayoutParams().width = 60; 
    RelativeLayout.LayoutParams head_params = (RelativeLayout.LayoutParams)enemy.getLayoutParams(); 
    head_params.setMargins(30, -20, 0, 0); //substitute parameters for left, top, right, bottom 
    enemy.setLayoutParams(head_params); 
} 

public void setStartEnd(int xS, int xE, int yS, int yE) { 
    startX = xS; 
    endX = xE; 
    startY = yS; 
    endY = yE; 
} 

public void followPath() { 
    TranslateAnimation animation = new TranslateAnimation(startX, endX, startY, endY); 
    animation.setDuration(6000); 
    animation.setFillAfter(true); 
    ((View) enemy).startAnimation(animation); 
} 

如果我錯過了任何東西或者您還有其他問題,請告訴我。

+1

'Thread.sleep(500);'在ui線程上不是一個好主意。如果你想重複使用'handler'。 – Raghunandan

+0

每當你發現自己在思考Thread.sleep時,尋找另一種設計。 Thread.sleep當然有使用(一些非常專業的用途),但定期更新UI線程不是其中之一。定時器上的Handler是要走的路。 – Simon

回答

0

你正在做一個單循環所有的用戶界面的變化,你是不是從btnRoundsClick(View view)返回每個UI變化後,這樣你就不會給Android系統的機會處理並可視化您的更改。 android中的UI主要基於消息。您的btnRoundsClick方法在此消息中執行,在更改UI後,另一條消息將顯示您的更改。

您可以修復它在幾個方面,例如使用Handler類,您可以:

Handler handler = new Handler(); // as a class field 

然後在btnRoundsClick(View view)handler.postDelayed(/*here runnable that does UI changes*/),在這個運行的,你可以計劃未來Runnable,你可以保留一些類變量保持重繪計數。


另一件事,是你不應該在UI線程中執行Thread.sleep,這可能會導致ANR(應用程序沒有響應),幾秒鐘後錯誤。 Android確保沒有UI消息會阻止消息隊列,並殺死任何違反此規則的應用程序。

4

問題是,爲什麼它會在循環中等待500ms 10次然後執行for循環中的所有其餘部分。

它沒有。它執行循環的迭代,每500ms執行一次 - 然後然後您允許UI線程實際顯示更新。在循環中添加一些日誌記錄,您會看到「每500毫秒一次迭代」行爲。

基本上,你阻止了UI線程。不要這樣做。

閱讀Android Processes and Threads guide瞭解更多詳情和備選方案。

0

難道你不能使用一個簡單的計時器?

new Timer().scheduleAtFixedRate(new TimerTask() { 

@Override 
       public void run() { 
//Your code here... 
} 

}, 0, 500); 

類似的東西...

+1

計時器任務也運行在不同的線程上。所以你不能更新用戶界面。你將不得不使用'runOnUiThread' – Raghunandan

+0

你是對的,需要添加runOnUiThread調用 – GhostDerfel