I know you can only change the text in tTxtViews from the UI thread but i cant seem to find a way to work with that.
I'll go in to a bit more details: I'm trying to have a TextView that displays the time passed, but I can't do it in a thread, or a method that keeps getting called.
can you help me with a way of doing this? because I'm pretty much out of ideas.
Thanks.
public class MainActivity extends Activity {
protected static final long TIMER_DELAY = 100;
private TextView tv;
protected Handler handler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView)findViewById(R.id.helloWorld);
handler = new Handler();
handler.post(timerTask);
}
private Runnable timerTask = new Runnable() {
public void run() {
Calendar now = Calendar.getInstance();
//format date time
tv.setText(String.format("%02d:%02d:%02d", now.get(Calendar.HOUR_OF_DAY), now.get(Calendar.MINUTE), now.get(Calendar.SECOND)));
//run again with delay
handler.postDelayed(timerTask, TIMER_DELAY);
}
};
}
I forgot add this, sorry. Don't forget do this:
#Override
public void onPause() {
if (handler != null)
handler.removeCallbacks(timerTask);
super.onPause();
}
And if you want resume app try this
#Override
public void onResume() {
super.onResume();
if (handler != null)
handler.post(timerTask);
}
Use this
new Thread(new Runnable() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
// Do what you want.
}
});
}
}).start();
or use a Handler:
Runnable r = new Runnable() {
#Override
public void run() {
// Do what you want.
}
};
Handler mHandler = new Handler();
mHandler.post(r);
Related
I am updating the text user types in a textview to database every 5 seconds.
The handler collects data from textview and save it to database.
But the update code runs even after I press back button and return to MainActivity.
How can I stop running the code after exiting from activity.
public class CreateBoxActivity extends AppCompatActivity {
Long current_BoxID = null, parent_BoxID = null;
Handler h=new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_create_box);
h.post(new Runnable(){ //Run this every five seconds to update the data
#Override
public void run() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String editeddate = sdf.format(Calendar.getInstance().getTime());
String titleText = ((EditText)findViewById(R.id.new_box_title)).getText().toString();
String descriText = ((EditText)findViewById(R.id.new_box_descri)).getText().toString();
Boxes nbx = new Boxes(1, null , titleText, descriText, editeddate, editeddate);
BoxesController.UpdateBox(nbx);
h.postDelayed(this,5000);
}
});
}
You need to release the handler resource when the activity is destroyed.
#override
protected void onDestroy() {
super.onDestroy();
h.removeCallbacksAndMessages(null);
h = null;
}
Create runnable outside of the method like :
Runnable runnable =new Runnable() {
#Override public void run() {
}
};
On your activity's onPause call:
h.removeCallback(runnable);
You can remove the handler in onPause
Runnable runnable =new Runnable() {
#Override public void run() {
}
};
new Handler().removeCallbacks(runnable);
Hi my app needs a realtime data from database and I'm posting it on my TextView and I can't update the TextView as the database updates. I tried using Timer but its still the same.
Here is my code,
public void startTimer() {
//set a new Timer
timer = new Timer();
//initialize the TimerTask's job
initializeTimerTask();
timer.schedule(timerTask, 0, 5000);
}
private void stopTimerTask() {
//stop the timer, if it's not already null
if (timer != null) {
timer.cancel();
timer = null;
}
}
public void initializeTimerTask() {
timerTask = new TimerTask() {
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
final AcceptCars Cars = (AcceptCars) getIntent().getSerializableExtra("cars");
renterLat.setText(Cars.renterLat);
renterLng.setText(Cars.renterLng);
Log.d(TAG,renterLat.getText().toString());
Log.d(TAG,renterLng.getText().toString());
}
});
}
};
}
And here is where I get the Cars.renterLat and Cars.renterLng,
public class AcceptCars implements Serializable {
#SerializedName("renterLat")
public String renterLat;
#SerializedName("renterLng")
public String renterLng;
}
This is the logic you should be following. I used a Handler instead of a Timer. Inside the run method you need to call your webservice and get the updated value from the db. Use runOnUiThread to update the value to the UI from a Thread.
See the code below,
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Handler taskHandler = new Handler();
taskHandler.postDelayed(myTask, 0);
}
private Runnable myTask = new Runnable(){
public void run() {
queryDb();
// repeat the task
taskHandler.postDelayed(this, 1000);
}
};
private void queryDb(){
new Thread(new Runnable() {
#Override
public void run() {
// call you webservice
String data = callWebservice();
// parse the data in to AcceptCars pojo class
AcceptCars Cars = parseData(data);
//update the UI
runOnUiThread(new Runnable() {
#Override
public void run() {
renterLat.setText(Cars.renterLat);
renterLng.setText(Cars.renterLng);
}
});
}
}).start();
}
You can even use countdown timer.
Here is the link https://developer.android.com/reference/android/os/CountDownTimer.html
TimerTasks are really hard to deal with IMO. You should use a Handler and call postDelayed to do something after a certain amount of time.
Alternatively, you can try out this timer class I wrote:
import android.os.Handler;
public class Timer {
private Handler handler;
private boolean paused;
private int interval;
private Runnable task = new Runnable () {
#Override
public void run() {
if (!paused) {
runnable.run ();
Timer.this.handler.postDelayed (this, interval);
}
}
};
private Runnable runnable;
public int getInterval() {
return interval;
}
public void setInterval(int interval) {
this.interval = interval;
}
public void startTimer () {
paused = false;
handler.postDelayed (task, interval);
}
public void stopTimer () {
paused = true;
}
public Timer (Runnable runnable, int interval, boolean started) {
handler = new Handler ();
this.runnable = runnable;
this.interval = interval;
if (started)
startTimer ();
}
}
It is really simple to use.
You can use it like this:
Timer timer = new Timer(new Runnable() {
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
final AcceptCars Cars = (AcceptCars) getIntent().getSerializableExtra("cars");
renterLat.setText(Cars.renterLat);
renterLng.setText(Cars.renterLng);
Log.d(TAG,renterLat.getText().toString());
Log.d(TAG,renterLng.getText().toString());
}
}
}
}, 5000, true);
How to do sample counter in Activity? This is not working.
public class MainActivity extends AppCompatActivity implements Runnable {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
run();
}
#Override
public void run() {
while (true) {
updateTv();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void updateTv() {
int counter = 100;
final TextView tv = (TextView) findViewById(R.id.tv);
tv.setText(String.valueOf(counter));
counter--;
}
}
In onCreate() you're starting an infinite loop inside of the UI thread, blocking it completely. Alternatively you could use a Handler for periodic updates. Maybe using a bigger delay and stop it sometime.
public class MainActivity extends AppCompatActivity implements Runnable {
private final Handler mHandler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
run();
}
#Override
public void run() {
updateTv();
mHandler.postDelayed(this, 17);
}
public void updateTv() {
int counter = 100;
final TextView tv = (TextView) findViewById(R.id.tv);
tv.setText(String.valueOf(counter));
counter--;
}
}
Anyway you should read What is the Android UiThread (UI thread) for sure.
Consider using Timer class which allows you to define a callback method that will be invoked at specified rate.
An example that fits your needs:
public class CounterActivity extends AppCompatActivity {
private TextView mCounterTextView;
private Timer mTimer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_counter);
mCounterTextView = (TextView) findViewById(R.id.counterTextView);
mTimer = new Timer();
mTimer.scheduleAtFixedRate(
new CounterTask(100), 0, TimeUnit.SECONDS.toMillis(1));
}
protected class CounterTask extends TimerTask {
protected int mCounter;
CounterTask(int initial) {
mCounter = initial;
}
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
mCounterTextView.setText(String.valueOf(mCounter));
}
});
--mCounter;
}
}
}
One more thing that should be noticed. As Timer executes it's own thread - it prevents you from updating your UI from outside of the main thread. In that case
you have to register a Runnable using runOnUiThread method.
Also, calling findViewById in a loop is not the best idea.
I am trying to create one application which checks battery status every one minute and update the UI with the battery Level.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
batteryPercent = (TextView) this.findViewById(R.id.battery);
while (true) {
runOnUiThread(mRunnable);
}
}
private Runnable mRunnable = new Runnable() {
#Override
public void run() {
getBatteryPercentage();
try {
Thread.sleep(60000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
`getBatteryPercentage()1 update a text view on UI.
When I call getBatteryPercentage() only once the code works fine, but when I try to run it in a loop like above, after few seconds I get Application Not Responding(ANR).
Is there any way to make the app wait for 60 seconds without getting ANR?
Don't do it with Sleep. Use a CountDownTimer instead.
CountDownTimer _timer;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
batteryPercent = (TextView) this.findViewById(R.id.battery);
_timer = new CountDownTimer(Long.MAX_VALUE, 60000) {
#Override
public void onTick(long millisUntilFinished)
{
getBatteryPercentage();
}
#Override public void onFinish() {}
};
_timer.start();
Don't forget to call _timer.cancel() before the Activity exits.
You can use Handler.postDelayed for this.
Handler handler = new Handler();
private Runnable mRunnable = new Runnable() {
#Override
public void run() {
getBatteryPercentage();
handler.postDelayed(mRunnable, 60000);
}
}
And then:
handler.postDelayed(mRunnable, 60000);
if you do something in android uithread more than 5 seconds,the application will show ANR toast.
you should do while loop in another thread,and use callback to refresh ui.you can do it like this:
new Thread(new Runnable(){
public void run(){
try{
Thread().sleep(6*1000);
updateUI();
}catch( Exception e){
e.print***();
}}}).start();
private void updateUI(){
runOnUiThread(new Runnable(){
getBatteryPercentage();
});
}
This is my code on Activity to Invalidate the canvas it is not invalidating. Means onDraw() is not getting called even once;
public GraphView view;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
view = GraphView(this,null);
runplotTimer();
}
public void runplotTimer()
{
Timer t = new Timer();
//Set the schedule function and rate
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
InvalidateTimer();
}
},1000,40);
}
public void InvalidateTimer()
{
this.runOnUiThread(new Runnable() {
#Override
public void run()
{
//Log.d(ALARM_SERVICE, "Timer of 40 miliseconds");
view.InvalidateGraph();
}
});
}
on View class this is method which is gettting called from Activity. other OnDraw declaration is same as required.
public void InvalidateGraph()
{
m_bCalledPlotRealTimeGraph = true;
invalidate(chanX_count1, 0, chanX_count1+7, graphheight);
}
Any help please ?
You are attempting to make changes to the View on a Timer Thread, which will not work. You need to call invalidate on the main (UI) thread:
((Activity) view.getContext()).runOnUiThread(new Runnable() {
#Override
public void run() {
invalidate(chanX_count1, 0, chanX_count1+7, graphheight);
}
});
you need to Start the Timer
Timer t = new Timer();
//Set the schedule function and rate
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
InvalidateTimer();
}
},1000,40);
t.start()
Instead of Timer use Handler.
class UpdateHandler implements Runnable {
#Override
public void run(){
handler.sendEmptyMessageAtTime(0, 1000);
handler.postDelayed(this, 1000);
}
}
private Handler handler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//Call your draw method
}
}
};
Inside onCreate and onResule write
if( mupdateTask == null )
mupdateTask = new UpdateHandler();
handler.removeCallbacks(mupdateTask);
Call your handler using
handler.postDelayed(mupdateTask, 100);