I am trying to make a clock, using a TextView :)
Someone here told me that I couldn't use normal threads to change the UI, but Handler or AsyncTask. I managed to get it working a few days ago, but was not a consistent thread.
Now what I want is a consistent thread that is always changing the text of my Textview. I tried using this, but didn't work, any help?
private void startClock() {
new Handler().postDelayed(new Runnable(){
#Override
public void run() {
while (true) {
final long millis = System.currentTimeMillis() - MainActivity.startedAt;
clock.setText("" + millis);
runOnUiThread (new Runnable() {
#Override
public void run() {
clock.setText("" + millis);
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}, 2000);
}
you should get rid of:
while(true) {
....
sleep(1000);
...
}
because this get your thread stuck forever. your program should work like this:
private Handler mHandler = new Handler();
#Override
public void onResume() {
super.onResume();
mHandler.removeCallbacks(mUpdateClockTask);
mHandler.postDelayed(mUpdateCLockTask, 100);
}
#Override
public void onPause() {
super.onPause();
mHandler.removeCallbacks(mUpdateClockTask);
}
private Runnable mUpdateClockTask = new Runnable() {
public void run() {
updateClock();
mHandler.postDelayed(mUpdateClockTask, 2000);
}
};
and inside updateClock() you do all your UI updates.
Look here for an example https://stackoverflow.com/a/11140429/808940
Also note that you have a duplicate line in your code:
clock.setText(""+millis);
It appears both in the runOnUiThread and in the main handler, it should only appear in the runOnUiThread runnable
Related
I would like to set an EditText with a timer thanks to CountDownTimer.
My EditText write second by second the number 3 and 2 but for the 1 there is a lag (it take 1,5 to 2 seconds).
Maybe I do it wrong.
This is my code :
CountDownTimer mCountDownTimer = new CountDownTimer(4000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
txt_timer.setText(String.valueOf(millisUntilFinished / 1000));
}
#Override
public void onFinish() {
txt_timer.setText("GO");
}
};
mCountDownTimer.start();
That is because the UI thread is doing too much work. Try running a new thread on the UI thread itself:
runOnUiThread(new Runnable() {
public void run()
{
//Insert your code
}
});
}
Let me know if you can;t get this to work!
The memory in the device cause the problem. I found a solution running a new thread.
I have to declare int i=4; before and use this code :
new Thread() {
public void run() {
while (i-- > 1) {
try {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
txt_timer.setText(String.valueOf(i));
}
});
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
txt_timer.setText("GO");
}
}.start();
I have a textview which i want to change with a thread and do it again and again (Like a digital clock). But i'm having problems with setting time between 2 changes. Here, the code:
display1 = (TextView) findViewById(R.id.textView1);
Thread timer2 = new Thread(){
#Override
public void run() {
synchronized (this){
runOnUiThread(new Runnable() {
#Override
public void run() {
int i = 0;
display1.setText("" + i);
try {
sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
display1.setText("" + (i+1));
}
});
}
}
};
timer2.start();
This sleep(2000); function makes textview invisible for the given time but i want it stand still till the next change. How can i do that?
But i'm having problems with setting time between 2 changes
Do NOT do sleep() on your UI thread. If you want to chain some actions with the delay, split your code into two runnables and the first one should set display1 and then post second runnable with the delay using postDelayed()
EDIT
want one of them to increase 3 per sec, and the other 5 per sec until they reach 1000 for instance
You can make your Runnable post itself until some criteria are met (i.e. time, counter value etc). Just at the end your Runnable check your conditions and if not met, call postDelayed(this, delay); and you are good.
You should use a Handler instead and dispatch your changes to the UI thread.
Handler mHandler = new Handler();
mHandler.post(new Runnable() {
#Override
public void run() {
// Code to be run right away
}
});
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
// Code to be run after 2 seconds
}
}, 2000);
Maybe split up what you need to do into separate methods. Here you have a UI method and a sleep method split up. Hope it helps
private void myMethod() {
new Thread() {
#Override
public void run() {
int i = 0;
doWorkOnUI(String.valueOf(i));
pause(2000);
doWorkOnUI(String.valueOf(i++));
}
}.start();
}
private void pause(int pauseTime) {
try {
Thread.sleep(pauseTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void doWorkOnUI(final String string) {
runOnUiThread(new Runnable() {
#Override
public void run() {
display1.setText(string);
}
});
}
I'm trying to make a timer that will do a certain thing after a certain amount of time:
int delay = 1000;
int period = 1000;
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
//Does stuff
}
}, delay, period);
However, the app crashes after the wait period. This is Java code, so it might not be entirely compatible with Android (like while loops). Is there something I'm doing wrong?
Something like this should work, create a handler, and wait 1 second :) This is generally the best way of doing it, its the most tidy and also probably the best on memory too as its not really doing too much, plus as it's only doing it once it is the most simple solution.
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
// do your stuff
}
}, 1000);
If you would like something to run every one second then something like this would be best:
Thread thread = new Thread()
{
#Override
public void run() {
try {
while(true) {
sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
If you want a GUI thread then something like this should work:
ActivityName.this.runOnUiThread(new Runnable()
{
public void run(){
try {
while(true) {
sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
If your app is crashing after the wait period, then your timer task is doing its job and executing your code on schedule. The problem must then be in your code where run() occurs (for example, you may be trying to update UI elements in a background thread).
If you post more code and your logcat, I can probably be more specific about the error you are getting, but your question was in regards to TimerTask.
Timer and also you can run your code on UI thread:
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
myTimer = new Timer();
myTimer.schedule(new TimerTask() {
#Override
public void run() {
timerMethod();
}
}, 0, 1000);
}
private void timerMethod(){
// This method is called directly by the timer
// and runs in the same thread as the timer.
// We call the method that will work with the UI
// through the runOnUiThread method.
this.runOnUiThread(timerTick);
}
private Runnable timerTick = new Runnable() {
public void run() {
// This method runs in the same thread as the UI.
// Do something to the UI thread here
}
};
I have one textview, which i can use to show countdown timer. I wanted to use Thread class which takes Runnable interface.
I wrote the following code for the same but it is gives run time error Unfortunately ThreadApp has Stopped
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;
public class MainActivity extends Activity implements Runnable
{
TextView tvTimer;
Thread timerThread;
int time=30;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvTimer =(TextView)findViewById(R.id.textView1);
timerThread= new Thread(this);
timerThread.start();
}
#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;
}
#Override
public void run()
{
try
{
Thread.sleep(1000);
tvTimer.setText((String.valueOf(time)).toString());
time--;
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
At the same time when i removed tvTimer.setText((String.valueOf(time)).toString()); it works fine. Can anyone provide me the solution. I am new in android.
You can use updating UI using RunOnUiThread like this
#Override
public void run()
{
try
{
Thread.sleep(1000);
runOnUiThread(new Runnable() {
public void run() {
tvTimer.setText((String.valueOf(time)).toString());
}
});
time--;
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
when i removed tvTimer.setText((String.valueOf(time)).toString()); it
works fine
because you are trying to change TextView text from non-ui Thread so use runOnUiThread or Handler for updating TextView from other Thread
new Thread(new Runnable() {
#Override
public void run() {
Thread.sleep(1000);
runOnUiThread(new Runnable() {
public void run() {
tvTimer.setText((String.valueOf(time)).toString());
time--;
}
});
}
You are trying to update ui in timer task. Timer task runs on a different thread. update ui on the ui thread. Use a handler or runonuithread
Handler m_handler;
Runnable m_handlerTask ;
m_handler = new Handler();
m_handlerTask = new Runnable()
{
#Override
public void run() {
tvTimer.setText((String.valueOf(time)).toString());
timer--;
// do something
m_handler.postDelayed(m_handlerTask, 1000); // instad of 1000 mention the delay in milliseconds
}
};
m_handlerTask.run();
Or use
#Override
public void run()
{
try
{
Thread.sleep(1000);
// should not call thread.sleep() bad design
// check the edit below
runOnUiThread(new Runnable(){
#Override
public void run(){
//update ui here
tvTimer.setText((String.valueOf(time)).toString());
}
});
time--;
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Edit: Using Thread.sleep() inside a thread is a bad design.
http://developer.android.com/training/articles/perf-anr.html
Quoting from the docs.
If you implement Thread or HandlerThread, be sure that your UI thread does not block while waiting for the worker thread to complete—do not call Thread.wait() or Thread.sleep(). Instead of blocking while waiting for a worker thread to complete, your main thread should provide a Handler for the other threads to post back to upon completion. Designing your application in this way will allow your app's UI thread to remain responsive to input and thus avoid ANR dialogs caused by the 5 second input event timeout.
To stops use this m_handler.removeCallbacks(m_handlerTask);
You are trying to update the UI element i.e., a TextView in your thread. You can't do this in a thread. Instead use a handler to post changes to your UI element as follows -
Handler handler = new Handler();
#Override
public void run()
{
try
{
Thread.sleep(1000);
handler.post(new Runnable()
{
public void run()
{
tvTimer.setText((String.valueOf(time)).toString());
}
time--;
});
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I have to display some data after every 10 seconds. Can anyone tell me how to do that?
There is an another way also that you can use to update the UI on specific time interval. Above two options are correct but depends on the situation you can use alternate ways to update the UI on specific time interval.
First declare one global varialbe for Handler to update the UI control from Thread, like below
Handler mHandler = new Handler();
Now create one Thread and use while loop to periodically perform the task using the sleep method of the thread.
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
while (true) {
try {
Thread.sleep(10000);
mHandler.post(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
// Write your code here to update the UI.
}
});
} catch (Exception e) {
// TODO: handle exception
}
}
}
}).start();
Probably the simplest thing to do is this:
while(needToDisplayData)
{
displayData(); // display the data
Thread.sleep(10000); // sleep for 10 seconds
}
Alternately you can use a Timer:
int delay = 1000; // delay for 1 sec.
int period = 10000; // repeat every 10 sec.
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask()
{
public void run()
{
displayData(); // display the data
}
}, delay, period);
Andrahu was on the right track with defining a handler. If you have a handler that calls your update functions you can simply delay the message sent to the handler for 10 seconds.
In this way you don't need to start your own thread or something like that that will lead to strange errors, debugging and maintenance problems.
Just call:
Handler myHandler = new MyUpdateHandler(GUI to refresh); <- You need to define a own handler that simply calls a update function on your gui.
myHandler.sendMessageDelayed(message, 10000);
Now your handleMessage function will be called after 10 seconds. You could just send another message in your update function causing the whole cycle to run over and over
There is Also Another way by Using Handler
final int intervalTime = 10000; // 10 sec
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Display Data here
}
}, intervalTime);
There is a Simple way to display some data after every 10 seconds.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launcher);
ActionStartsHere();
}
public void ActionStartsHere() {
againStartGPSAndSendFile();
}
public void againStartGPSAndSendFile() {
new CountDownTimer(11000,10000) {
#Override
public void onTick(long millisUntilFinished) {
// Display Data by Every Ten Second
}
#Override
public void onFinish() {
ActionStartsHere();
}
}.start();
}
Every 10 seconds automatically refreshed your app screen or activity refreshed
create inside onCreate() method i tried this code will work for me
Thread t = new Thread() {
#Override
public void run() {
try {
while (!isInterrupted()) {
Thread.sleep(1000);
runOnUiThread(new Runnable() {
#Override
public void run() {
//CALL ANY METHOD OR ANY URL OR FUNCTION or any view
}
});
}
} catch (InterruptedException e) {
}
}
};t.start();