如何在 android studio 中正确使用 postDelayed()?
Posted
技术标签:
【中文标题】如何在 android studio 中正确使用 postDelayed()?【英文标题】:how to use postDelayed() correctly in android studio? 【发布时间】:2017-07-11 18:47:23 【问题描述】:我有一个 countDownTimer,如果用户在 12 秒内没有点击 gameButton,我希望调用 gameOver 方法。问题我要么在 countDownTimer 为 12 时立即调用游戏功能,要么计时器一直在倒计时。所以我尝试使用 postDelayed() 方法给用户一整秒的时间来点击按钮并让 countDownTimer 继续,但由于我的代码现在游戏在 12 点停止。
import android.app.Activity;
import android.os.CountDownTimer;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class GameScreen extends Activity
private TextView time;
private Button start;
private Button cancel;
private Button gameButton;
private CountDownTimer countDownTimer;
public static int count = 0;
public static int countFail = 0;
final Handler handler = new Handler();
final Runnable r = new Runnable()
public void run()
handler.postDelayed(this, 1000);
gameOver();
;
private View.OnClickListener btnClickListener = new View.OnClickListener()
@Override
public void onClick(View v)
switch(v.getId())
case R.id.start_ID :
start();
break;
case R.id.cancel :
cancel();
break;
case R.id.gameButton_ID :
gameButton();
break;
;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game_screen);
start = (Button) findViewById(R.id.start_ID);
start.setOnClickListener(btnClickListener);
cancel = (Button) findViewById(R.id.cancel);
cancel.setOnClickListener(btnClickListener);
time = (TextView) findViewById(R.id.time);
gameButton = (Button) findViewById(R.id.gameButton_ID);
gameButton.setOnClickListener(btnClickListener);
public void start()
time.setText("16");
//This doesn't work and makes app crash when you hit start button
countDownTimer = new CountDownTimer(16 * 1000, 1000)
@Override
public void onTick(long millsUntilFinished)
time.setText("" + millsUntilFinished / 1000);
//turns textview string to int
int foo = Integer.parseInt(time.getText().toString());
if(time.getText().equals("12"))
r.run();
public void onFinish()
time.setText("Done !");
;
countDownTimer.start();
private void cancel()
if(countDownTimer != null)
countDownTimer.cancel();
countDownTimer = null;
private void gameOver()
Toast.makeText(getApplicationContext(), "You scored " + count, Toast.LENGTH_SHORT).show();
count = 0;
countFail = 0;
cancel();
private void gameButton()
int foo = Integer.parseInt(time.getText().toString());
if(foo % 2 == 0 )
Toast.makeText(getApplicationContext(), "PASS", Toast.LENGTH_SHORT).show();
handler.removeCallbacks(r);
++count;
else
gameOver();
【问题讨论】:
【参考方案1】:您几乎正确地使用了postDelayed(Runnable, long)
,但并不完全正确。让我们看看你的 Runnable。
final Runnable r = new Runnable()
public void run()
handler.postDelayed(this, 1000);
gameOver();
;
当我们调用r.run();
时,它要做的第一件事就是告诉您的handler
在1000 毫秒后运行相同的Runnable,然后调用gameOver()
。这实际上会导致您的 gameOver()
方法被调用两次:一次是立即调用,第二次是在 Handler 完成后等待 1000 毫秒。
相反,您应该将 Runnable 更改为:
final Runnable r = new Runnable()
public void run()
gameOver();
;
然后这样称呼它:
handler.postDelayed(r, 1000);
希望这会有所帮助。
【讨论】:
gameOver()
不是每秒无限调用,而不是被调用两次?它看起来像无限递归。【参考方案2】:
以下是我使用的代码,它与公认的答案相同,但编写和理解起来非常简单。
final Handler handler = new Handler();
handler.postDelayed(new Runnable()
@Override
public void run()
//Write whatever to want to do after delay specified (1 sec)
Log.d("Handler", "Running Handler");
, 1000);
【讨论】:
【参考方案3】: Thread(Runnable
// background work here ...
Handler(Looper.getMainLooper()).postDelayed(Runnable
// Update UI here
, 10000) //it will wait 10 sec before upate ui
).start()
【讨论】:
【参考方案4】:不推荐使用无参数的 Handler 构造函数,并且不使用 lambdas 也会使代码看起来很笨拙,所以话虽如此,下面是它看起来更现代的用法:
final Runnable _r_ = new Runnable()...;
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(() -> _r_.run(), 666);
您也可以更新它以使用方法参考
handler.postDelayed(_r_::run(), 666);
或者更简单,只需要一个限定符
handler.postDelayed(_r_, 666);
【讨论】:
以上是关于如何在 android studio 中正确使用 postDelayed()?的主要内容,如果未能解决你的问题,请参考以下文章
如何强制 Android Studio 生成具有开发人员正确名称的文档