i creating for stopwatch with start,stop i use following code it started but not stop. please help me.
my code:
public class StopWatch2 extends Activity implements Runnable{
// text view influenced by the Thread
private TextView threadModifiedText;
int time=0;
Button b1,b2,b3;
/** Called when the activity is first created. */
Thread currentThread = new Thread(this);
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.stopwatch);
b1=(Button)findViewById(R.id.button1);
b2=(Button)findViewById(R.id.button2);
b3=(Button)findViewById(R.id.button3);
threadModifiedText = (TextView) findViewById(R.id.textView1);
b1.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
currentThread.start();
}
});
b2.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
currentThread.stop();
}
});
}
//Method you must override to control what the Thread is doing
#Override
public void run(){
try {
while(true){
currentThread.sleep(1000, 0);
threadHandler.sendEmptyMessage(0);
}
// signaling things to the outside world goes like this
} catch (InterruptedException e) {
}
}
private Handler threadHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
time++;
threadModifiedText.setText(""+time);
}
};
}
I think You should use a class level variable boolean shouldRun = true ;
in your run() method while should be used like this way
while(shouldRun)
{
//implementation
}
and in your b2.onClickListener() change shouldRun = false;
Edit:
For suspend and resume you can change the value of shouldRun to shouldRun = true; in the listener for resume button. Remember that when you stop the updates you should reset the time also. and in suspend the time should be remain same.
I implemented stopwatch for rotational puzzles solving time measurements and I have approached it somewhat differently.
For time measurements I use Handler object that triggers after DISPLAY_UPDATE_TIMEOUT. It is time after which you update display about time elapsed.
To start counting I use:
mLastStartTimestamp = System.currentTimeMillis();
mRepetitiveTimeoutHandler.postDelayed(processWatchTimer, DISPLAY_UPDATE_TIMEOUT);
and to stop it
mRepetitiveTimeoutHandler.removeCallbacks(processWatchTimer);
mStartStopElapsed = System.currentTimeMillis() - mLastStartTimestamp ;
updateTimeDisplay();
On each trigger of the handler I do the following:
private Runnable processWatchTimer = new Runnable()
{
public void run()
{
mRepetitiveTimeoutHandler.postDelayed(processWatchTimer, DISPLAY_UPDATE_TIMEOUT);
updateTimeDisplay();
}
};
Related
This question already has answers here:
Update TextView Every Second
(11 answers)
Closed 4 years ago.
i want to update my textview every second.
on button click i am calling one method,
loopMethod(milli); //suppose milli= 50000 i.e 50 sec.
so my loopMethod(int m) is as follows:
public void loopMethod(int m){
timer=(TextView) findViewById(R.id.timerText);
if(m>=1000){
try {
timer.setText(""+m);//timer is a textview
System.out.println(m);
m=m-1000;
Thread.sleep(1000);
} catch(InterruptedException ex) {
ex.printStackTrace();
}
loopMethod(m);
}
}
so what i am expecting is, my timer textview should print the value of m every second.
but i am getting only console output i.e system.out.println(m)...
printing value on console working fine...
but its not updating my textview at all
You can use following code:
Runnable updater;
void updateTime(final String timeString) {
timer=(TextView) findViewById(R.id.timerText);
final Handler timerHandler = new Handler();
updater = new Runnable() {
#Override
public void run() {
timer.setText(timeString);
timerHandler.postDelayed(updater,1000);
}
};
timerHandler.post(updater);
}
In this line:
timerHandler.post(updater);
time will set for the first time. i.e, updater will execute. After first execution it will be posted after every 1 second time interval. It will update your TextView every one second.
You need to remove it when the activity destroys, else it will leak memory.
#Override
protected void onDestroy() {
super.onDestroy();
timerHandler.removeCallbacks(updater);
}
Hope it will help you.
You should use RxJava library to do so:
Subscription s =
Observable.interval(1, TimeUnit.SECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(v -> {
// update your ui here
}, e -> {
});
// call when you no longer need an update:
if (s != null && !s.isUnsubscribed()){
s.unsubscribe();
s = null;
}
That's it. Do NOT use .postDelay(), Timer because it is error prone.
You might want to consider using the Chronometer class: https://developer.android.com/reference/android/widget/Chronometer.html
just use timer.start(); on the button click
Using handler can be used like this
TextView timer;
int m =0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
timer=(TextView) findViewById(R.id.timerText);
Handler handler = new UpdateHandler();
m = 10;
handler.sendEmptyMessageDelayed(1, 1000);//start after 1000
}
class UpdateHandler extends Handler{
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
timer=(TextView) findViewById(R.id.timerText);
timer.setText("Text :" +m);
m = m-1000;
sendEmptyMessageDelayed(1, 1000); //seng again after 1000
//add some stop logic
break;
default:
break;
}
}
}
Try this code Initialize textview in
onCreate
timer=(TextView) findViewById(R.id.timerText);
public void loopMethod(int m){
if(m>=1000){
try {
System.out.println(m);
m=m-1000;
final ScheduledThreadPoolExecutor c = new ScheduledThreadPoolExecutor(1);
c.schedule(new Runnable() {
#Override
public void run() {
timer.setText(""+m);//timer is a textview
c.shutdownNow();
}
}, 1, TimeUnit.SECONDS);
} catch(InterruptedException ex) {
ex.printStackTrace();
}
loopMethod(m);
}
}
I've added some logics to stop the Timer. If you have any qyestion, ask freely
private int m = 0;
private int milliseconds = 1000;
public void loopMethod(int m){
timer=(TextView) findViewById(R.id.timerText);
Timer t = new Timer();
//schedule a timer
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
timer.setText(String.valueOf(m));//avoid using composite string in the setText
System.out.println(String.valueOf(m));
//remove from the total the amount of millisecond passed
m=m-milliseconds;
if(m <= milliseconds) { //or <= what you want
//stop the timer repeatitions
t.cancel();
}
}
});
}
//"0" is the amount of time to wait for the timer to start
//"milliseconds" is the duration
},0,milliseconds);
}
Add
For a correct analysis you should add more infos in your question. the problem of not-updating textview might be caused by the setText("" + int) because it's always better to avoid the setText with an int. I edited it with String.valueOf, but if it's not working you should add the xml and the onCreate
Hope this helped
I have created timer for seconds.
public class TimerForSeconds extends AppCompatActivity {
private int seconds = 60;
private TextView tvTimer;
private Handler mHandler;
private Runnable runnable = new Runnable() {
#Override
public void run() {
if(seconds == 0){
mHandler.removeCallbacks(runnable);
}
else{
tvTimer.setText(seconds + "");
seconds--;
mHandler.postDelayed(runnable,1000);
}
}
};
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_activity);
tvTimer = (TextView) findViewById(R.id.tv_timer);
mHandler = new Handler();
mHandler.postDelayed(runnable,1000);
}
}
//and also removCallback onDestroy too.
I'm writing an app that will display the current download speed which will be updated every second. My Runnable class is able to update the UI with the value, but when I try to place it inside a loop so that it will continuously run and update the UI TextView every second, the app now hangs.
This is my MainActivity.java:
public class MainActivity extends Activity implements SpeedMeter.TaskRunnableSpeedMeterMethods{
private Thread mSpeedMeterThread;
private Handler mHandler;
private TextView downloadSpeedOutput;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
downloadSpeedOutput = (TextView) findViewById(R.id.speed);
mHandler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message inputMessage) {
SpeedMeter speedMeter = (SpeedMeter) inputMessage.obj;
downloadSpeedOutput.setText(Long.toString(speedMeter.getmDownloadSpeedKB()));
}
};
SpeedMeter speedMeter = new SpeedMeter(this);
speedMeter.run();
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(this, MainActivity.class);
}
#Override
public void setSpeedMeterThread(Thread currentThread) {
mSpeedMeterThread = currentThread;
}
#Override
public void setInternetSpeed(SpeedMeter speedMeter) {
Message completeMessage = mHandler.obtainMessage(1, speedMeter);
completeMessage.sendToTarget();
}
}
And here's the other SpeedMeter.java:
public class SpeedMeter implements Runnable {
final TaskRunnableSpeedMeterMethods mMainActivity;
private long mDownloadSpeedKB;
public SpeedMeter(TaskRunnableSpeedMeterMethods mainActivity) {
mMainActivity = mainActivity;
}
#Override
public void run() {
mMainActivity.setSpeedMeterThread(Thread.currentThread());
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
// while(true) {
long rxBytesPrevious = TrafficStats.getTotalRxBytes();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long rxBytesCurrent = TrafficStats.getTotalRxBytes();
long downloadSpeed = rxBytesCurrent - rxBytesPrevious;
setmDownloadSpeedKB(downloadSpeed/1000);
mMainActivity.setInternetSpeed(this);
// }
}
public long getmDownloadSpeedKB() {
return mDownloadSpeedKB;
}
public void setmDownloadSpeedKB(long mDownloadSpeedKB) {
this.mDownloadSpeedKB = mDownloadSpeedKB;
}
interface TaskRunnableSpeedMeterMethods {
void setSpeedMeterThread(Thread currentThread);
void setInternetSpeed(SpeedMeter speedMeter);
}
}
Any help will be appreciated!
You didnt start your runnable as a new thread instead you called the run function like a normal function (so u do the while loop on ur UI thread which blocks it)
replace
speedMeter.run();<br />
SpeedMeter speedMeter = new SpeedMeter(this);
with
new Thread(new SpeedMeter(this)).start();
see https://docs.oracle.com/javase/tutorial/essential/concurrency/runthread.html for more infos on how to start a Runnable :)
The ideal way to do this would be to create an AsyncTask that would post a message to your UI thread, after it complete the task in the doInBackground() call.
Standards
also the interface structure you are following does not make sense and does not follow good standards. Usually an interface is used as a callback, which is basically what you are doing. But the standard is to say onSomethingChangedA() or onSomethingChangedB() from OnSomethingChangedListener interface.
I think your loop is always true so app hangs its better to create a boolean and use while(mboolean) and put this in your loop
if(something){
mboolean=false;
}
you can also use CountDownTimer.
for example:
new CountDownTimer(miliseconds,1000)
//if you have download speed and download size you can find miliseconds
#Override
public void onTick(long l) {
//something you want to do every seconds
}
#Override
public void onFinish() {
//something you want to do on finish
}
My goal is when the user tap start button, letters "o" "n" "o" "m" and so forth will appear at the center of the screen. "o" will appear first then after a few seconds will be replaced by "n" then "o" and so forth.
note: for brevity, i just make the guessword = onomatopoeia, first. In reality, guessword will changes every time i tap the start bottom.
this is the code:
private String guessword = "onomatopoeia";
private TextView showchar;
private int n = guessword.length();
private char letArray[]= guessword.toCharArray();;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_play);
addStartListener();
}
public void addStartListener(){
Button start = (Button) findViewById(R.id.start);
showchar = (TextView) findViewById (R.id.charView);
start.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
Thread thread = new Thread()
{
#Override
public void run() {
try {
for(int i = 0 ; i < n ; i++) {
sleep(1000);
showchar.setText(letArray[i]);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
}
});
}
thanks for the help
I decided to implement runonuithread but still it crashes:
this is the updated version:
private String guessword = "onomatopoeia";
private TextView showchar;
private int n = guessword.length();
private char letArray[]= guessword.toCharArray();
private Handler handler;
private int i = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_play);
handler = new Handler();
showchar = (TextView) findViewById (R.id.charView);
}
public void startGame(View view){
new Thread() {
public void run() {
while(i++ < n) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
showchar.setText(letArray[i]);
}
});
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
use this code for setting the text in your textview
runOnUiThread(new Runnable() {
#Override
public void run() {
showchar.setText(letArray[i]);
}
});
You are updating ui from a thread which is not possible.
showchar.setText(letArray[i]);
UI must be updated ui thread.
All you are doing is repeatedly setting value to TextView you can use Handler with a delay for this purpose.
You could use runOnUiThread also but i don't see the need for a thread for what you are doing.
Use a Handler. You can find an example #
Android Thread for a timer
So I'm trying to write a stopwatch app that displays time in milliseconds, but for some reason it won't work. Basically I have just a togglebutton that, after being pressed, starts printing the milliseconds from the start time to the current time... In the simulator though, the app locks up. What's wrong?
public class testing extends Activity {
/** Called when the activity is first created. */
Button start,stop;
long init,now,time;
TextView display;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
display = (TextView) findViewById(R.id.chronometer1);
final ToggleButton passTog = (ToggleButton) findViewById(R.id.onoff);
passTog.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
init=System.currentTimeMillis();
while(passTog.isChecked())
{
now=System.currentTimeMillis();
time=now-init;
display.setText("t: " + time);
}
}
});
}
}
You definitely should not run a busy loop like you are doing inside the OnClickListener. That's why the app locks up. You need to let the rest of the system have its say. Also, it doesn't make sense to update the display more than once every 30 milliseconds or so, since that's about the fastest that the human eye can track. Also, you might want to suspend your timer when the activity is paused. Here's a version that does all that:
public class testing extends Activity {
/** Called when the activity is first created. */
Button start,stop;
long init,now,time,paused;
TextView display;
Handler handler;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler = new Handler();
setContentView(R.layout.test);
display = (TextView) findViewById(R.id.chronometer1);
final ToggleButton passTog = (ToggleButton) findViewById(R.id.onoff);
final Runnable updater = new Runnable() {
#Override
public void run() {
if (passTog.isChecked()) {
now=System.currentTimeMillis();
time=now-init;
display.setText("t: " + time);
handler.postDelayed(this, 30);
}
}
};
passTog.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
init = System.currentTimeMillis();
handler.post(updater);
}
});
}
#Override
protected void onPause() {
super.onPause();
paused = System.currentTimeMillis();
}
#Override
protected void onResume() {
super.onResume();
init += System.currentTimeMillis() - paused;
}
}
You put the setText() method in your onClick(), so will you click the button every second?
Its not even a thread!
Try the onTick() method of CountDownTimer class instead.
i doing simple stop watch with [start/pause] and [reset] button. problem occur when i pressed start button after pause. the run method is not calling. please help me.
my code is
public class StopWatch3 extends Activity implements Runnable{
// text view influenced by the Thread
private TextView threadModifiedText;
int time=0;
Button b1,b2,b3;
boolean shouldRun = false;
/** Called when the activity is first created. */
Thread currentThread = new Thread(this);
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.stopwatch);
b1=(Button)findViewById(R.id.button1);
b2=(Button)findViewById(R.id.button2);
b3=(Button)findViewById(R.id.button3);
threadModifiedText = (TextView) findViewById(R.id.textView1);
Log.e("before",""+currentThread.getState());
b1.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
Log.e("stopw",(String) b1.getText());
if(b1.getText().toString().equals("start")){
if(currentThread.getState()==Thread.State.NEW){
currentThread.start();
Log.e("after",""+currentThread.getState());
shouldRun = true;
b1.setText("pause");
}
else{
shouldRun = true;
b1.setText("pause");
}
}
else if(b1.getText().toString().equals("pause")){
shouldRun = false;
b1.setText("start");
}
}
});
b2.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
time=0;
}
});
}
#Override
public void run(){
try {
while(shouldRun){
Thread.sleep(1000);
threadHandler.sendEmptyMessage(0);
}
} catch (InterruptedException e) {
}
}
private Handler threadHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
time++;
threadModifiedText.setText(""+time);
}
};
}
You cannot start thread after it finishes it's job, and his state is no longer NEW anyway, you'll have to create a new thread in this case.
When you press "start" the second time, you reach this part:
else{
shouldRun = true;
b1.setText("pause");
}
And nothing in this code will make the thread run again of course...
I think your thread just runs to an end when you set shouldRun to false.
Enclose your while loop into another while loop that is true as long as your program runs.