2014-01-15 49 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