我正在尝试创建一个简单的Android秒表应用程序。每次按下开始按钮时,我都无法冻结应用程序。我从在线阅读各种内容中了解到,它挂起的原因是我在UI线程中运行了一个while循环,以便应用程序不会崩溃,而while循环必须在某个不同的地方。 XDA论坛上的帖子表明遇到此问题的人应该使用AsyncTask来完成此任务。我无法准确理解如何使用AsyncTask来执行此操作。
TL; DR:我正在尝试计算时间,然后用相应的时间更新textview
在UI线程中使用while循环的原始代码
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity
{
Button start, stop, reset;
TextView time;
boolean timeStopped = false;
long timeInNanoSeconds, startTimeInNanoSeconds;
double timer;
public double getTimeInSeconds()
{
timeInNanoSeconds = System.nanoTime() - startTimeInNanoSeconds;
double timeSeconds = (double) timeInNanoSeconds / 1000000000.0;
double roundOff = Math.round(timeSeconds * 100.0) / 100.0;
return roundOff;
}
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start = (Button) findViewById(R.id.startButton);
stop = (Button) findViewById(R.id.stopButton);
reset = (Button) findViewById(R.id.resetButton);
time = (TextView) findViewById(R.id.timeField);
start.setOnClickListener(new View.OnClickListener()
{
public void onClick(View arg0)
{
startTimeInNanoSeconds = System.nanoTime();
while(timeStopped == false)
{
double timer = getTimeInSeconds();
String stringTimer = Double.toString(timer);
CharSequence sequenceTimer = stringTimer;
time.setText(sequenceTimer);
}
}
});
stop.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
}
});
reset.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
time.setText("");
}
});
}
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
编辑:使用处理程序的工作版
import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
Button start, stop, reset;
TextView time;
Handler m_handler;
Runnable m_handlerTask;
int timeleft = 0;
boolean timeStopped;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start = (Button) findViewById(R.id.buttonStart);
stop = (Button) findViewById(R.id.buttonStop);
reset = (Button) findViewById(R.id.buttonReset);
time = (TextView) findViewById(R.id.textTime);
start.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
timeStopped = false;
m_handler = new Handler();
m_handlerTask = new Runnable()
{
public void run() {
if(timeStopped == false){
if(timeleft > -1) {
Log.i("timeleft","" + timeleft);
time.setText(String.valueOf(timeleft));
timeleft++;
}
else{
m_handler.removeCallbacks(m_handlerTask);
}
}
m_handler.postDelayed(m_handlerTask, 1000);
}
};
m_handlerTask.run();
}
});
stop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
timeStopped = true;
m_handler.removeCallbacks(m_handlerTask);
}
});
reset.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
timeStopped = true;
m_handler.removeCallbacks(m_handlerTask);
timeleft = 0;
time.setText(String.valueOf(timeleft));
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
答案 0 :(得分:2)
doInbackground
。你无法从后台更新ui
time.setText(sequenceTimer);
// should be in a ui thread.
在runOnUithread
中使用onPostExecute
或setText。
您可以根据需要使用处理程序,计时器任务或CountDowntimer。
编辑:
使用处理程序
public class MainActivity extends Activity
{
Button start;
TextView time;
Handler m_handler;
Runnable m_handlerTask ;
int timeleft=100;
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start = (Button) findViewById(R.id.button1);
time = (TextView)findViewById(R.id.textView1);
start.setOnClickListener(new View.OnClickListener()
{
public void onClick(View arg0)
{
m_handler = new Handler();
m_handlerTask = new Runnable()
{
@Override
public void run() {
if(timeleft>=0)
{
// do stuff
Log.i("timeleft",""+timeleft);
time.setText(String.valueOf(timeleft));
timeleft--;
}
else
{
m_handler.removeCallbacks(m_handlerTask); // cancel run
}
m_handler.postDelayed(m_handlerTask, 1000);
}
};
m_handlerTask.run();
}
});
}
}
答案 1 :(得分:2)
在我看来,AsyncTask并不适合你,因为在我看来这是一次单枪行动。
我会建议这样的事情:
private ScheduledExecutorService exec;
private void startExec() {
shutDownExec();
exec = Executors.newSingleThreadScheduledExecutor();
exec.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
// this starts immediately and is run once every minute
double timer = getTimeInSeconds();
String stringTimer = Double.toString(timer);
CharSequence sequenceTimer = stringTimer;
runOnUiThread(new UpdateUI(R.id.yourtime_textview, sequenceTimer));
}
}, 0, 1, TimeUnit.MINUTES); // adjust how often run() is executed here
}
private void shutDownExec() {
if (exec != null && !exec.isTerminated()) {
exec.shutdown();
}
}
private class UpdateUI implements Runnable {
private String mText;
private TextView mTv;
public UpdateUI(int textviewid, String text) {
this.mTv = (TextView) findViewById(textviewid);
this.mText = text;
}
@Override
public void run() {
mTv.setText(mText);
}
}
答案 2 :(得分:1)
我最近不得不做一个类似的任务,我使用以下代码创建了一个单独的线程。它允许您按照我认为适合您的任务的设定时间间隔进行更新。
希望它有所帮助。
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
public class AutomationTreadClass {
Activity refToUIActivity;
//Declare the timer
Timer t = new Timer();
//pass UI activity so you can call update on it
AutomationTreadClass( Activity callingActivity ){
refToUIActivity = callingActivity;
startTimerTread();
}
private void startTimerTread(){
//Set the schedule function and rate
t.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
//do any updates to the time you need to do here
updateLevelMeter();
}
},
//Start Time of thread
0,
//interval of updates
30);
}
private void updateLevelMeter() {
refToUIActivity.runOnUiThread(new Runnable() {
public void run() {
//access what ever UI comment you need to here. like giving you textview a value.
}
});
}
}