I use the following code to update a timer in my UI.
The problem with this code however, is that with each second passed, it updates by +1 second.
I think I understand why this happens, however I don't know how to fix it.
private Handler mHandler = new Handler();
....
private Runnable mUpdateTimeTask = new Runnable() {
public void run() {
mDifference = System.currentTimeMillis() - mStartTime;
workSum = workSum + mDifference;
TextViewTime.setText("Time so far: " + formatTime(workSum));
mHandler.postDelayed(this, 1000);
}
};
public void onClick(View v) {
switch (v.getId()) {
case R.id.start_button:
startButton.setEnabled(false);
stopButton.setEnabled(true);
if (mStartTime == 0L) {
mStartTime = System.currentTimeMillis();
mHandler.removeCallbacks(mUpdateTimeTask);
mHandler.postDelayed(mUpdateTimeTask, 1000);
}
Help would be greatly appreciated!
workSum = workSum + mDifference; seems to be your problem, because mDifference is incrementing each time.
I think workSum = mDifference; will solve it, or even
mDifference = System.currentTimeMillis() - mStartTime;
TextViewTime.setText("Time so far: " + formatTime(mDifference));
Related
I have a tune in my android app. I have added a feature that if user selects a time then the tune will repeat until the time ends. I have also added the feature of infinite time but when I run my app goes in ANR (not responding) mode.
if(tinydb.getString("timer").equals("infinity"))
{
boolean valid = true; //Here i want to play the tune for infinite time
while(valid)
{
water_player = MediaPlayer.create(MainActivity.this, R.raw.water);
water_player.start();
}
}
else
{
while(!timerText.equals("0h: 0m: 1s")) //Here i want to play the tune until the timer gets zero
{
water_player = MediaPlayer.create(MainActivity.this, R.raw.water);
water_player.start();
}
you can use setLooping for the first case
and for the second case
final Runnable r = new Runnable() {
public void run() {
water_player.stop();
}
};
handler.postDelayed(r, 1000); //your time in millisecond
with your code :
if(tinydb.getString("timer").equals("infinity"))
{
water_player = MediaPlayer.create(MainActivity.this, R.raw.water);
water_player.setLooping(true);
water_player.start();
}
else
{
water_player = MediaPlayer.create(MainActivity.this, R.raw.water);
water_player.start();
final Runnable r = new Runnable() {
public void run() {
water_player.stop();
}
};
handler.postDelayed(r, 1000); //your time in millisecond
}
Use countdownTimer to complete your goal in which you can set countdown timer till x seconds manually. when countdown finish process it will go to finish method and execute finish method code
CountDownTimer cntr_aCounter = new CountDownTimer(3000, 1000) {
public void onTick(long millisUntilFinished) {
mp_xmPlayer2.start();
}
public void onFinish() {
//code fire after finish
mp_xmPlayer2.stop();
}
};cntr_aCounter.start();
If you have only 2 cases, use a boolean.
boolean infinitely;
if(infinitely == true){
water_player = MediaPlayer.create(MainActivity.this, R.raw.water);
water_player.start();
}
else {
water_player = new MediaPlayer.create(MainActivity.this, R.raw.water);
water_player.start();
Handler handler = new Handler();
handler.postDelayed(new Runnable(){
water_player.stop();
}
}
, 2000);
The handler method will be executed when 2sec passed. (put your own desired time).
what I'm trying to do:
My app connects with a Bluetooth accelerometer and gets acceleration data every 50ms. I want to check for these with a Runnable. And this worked fine. However, for the complete app I added two CountDownTimers:
1) introTimer(), which runs in an AlertDialog and counts down from 3. OnFinish() calls (i) my Runnable, that deals with new acceleration data and (ii) a second timer called
2) mainTimer(), which counts down from 20 and refreshes a TextView on the UI.
My problem is, that my Runnable is only executed once when it is first called. Why is that? Apparently I have not yet understood the threading principles behind this. My next step (probably going to be complicated) is to refresh ImageViews every 50ms (or maybe less often, but still with a relatively high frequency) on the UI, depending on the accelerometer data.
I have thought about deleting the Runnable and putting my calculations in the CountDownTimer, but this might be difficult or inaccurate with the timing/frequency/periods. What do you think?
Here are the code parts. If you think other parts are relevant, I can post them as well:
startButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
LayoutInflater layoutInflater = getActivity().getLayoutInflater();
View promptView = layoutInflater.inflate(R.layout.intro_timer_prompt, null);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
final TextView introTimer = (TextView) promptView.findViewById(R.id.introTimer);
builder.setView(promptView);
AlertDialog alertD = builder.create();
alertD.show();
introTimer(introTimer, alertD);
}
private void introTimer(final TextView introTimer, final AlertDialog alertD) {
new CountDownTimer(4*1000, 1000) {
public void onTick(long millisUntilFinished) {
introTimer.setText( ""+ (millisUntilFinished / 1000));
}
public void onFinish() {
alertD.cancel();
// mainTimer();
clearArrayLists();
mHandler = new Handler();
mHandlerTask.run();
mainTimer();
}
}.start();
}
private void mainTimer() {
new CountDownTimer((int)DURATION*1000, 10) {
public void onTick(long millisUntilFinished) {
//mTimerView.setText("seconds remaining: " + millisUntilFinished / 1000 + ":" + millisUntilFinished / 1000. );
long millisecs = Math.round(millisUntilFinished % 1000 / 100);
mTimerView.setText("seconds remaining: " + millisUntilFinished / 1000 + ":" + millisecs );
}
public void onFinish() {
String energy = new DecimalFormat("#.##").format(accumulatedKineticEnergy.get(accumulatedKineticEnergy.size()-1));
mTimerView.setText("Accumulated Energy is " + energy + " Joule.");
}
}.start();
}
Runnable mHandlerTask = new Runnable() {
#Override
public void run() {
Log.i(TAG, "executed only once :( ");
if (a_x.size() < DURATION/INTERVAL) {
try {
calcAccList();
//...calc things...;
mHandler.postDelayed(this, (long) (1000*INTERVAL));
} catch (Exception e) {
e.getMessage();
}
}
else {
mHandler.removeCallbacks(mHandlerTask);
}
}
};
A countdown timer doesn't repeat itself when it expires, but you need to start it again. Maybe you can use the AlarmManager in this case to have a better design.
I get notification with socket.io to start a countdown timer in my android app. I use a Handler to send data from the socket.io callbacks to the UI thread. Handler messages work perfect. But starting the countdown timer from the handler doesn't work (onTick() function won't called). If I start it with the UI element, everything is ok. What is the best way to do it, when the countdown timer is operated not from the UI thread?
mHandler = new Handler(){
public void handleMessage(Message inputMessage) {
mBattle = (Battle) inputMessage.obj;
switch (inputMessage.what) {
case NO_BATTLE:
System.out.println("got message NO_BATTLE");
break;
//.................
case START_BATTLE:
startCountdownTimer(mBattle.getCountdown());
System.out.println("got message START_BATTLE");
break;
}
}
and the countdown timer function:
private void startProgressBar(final int time){
if (time != 0) {
new CountDownTimer(time, 1000) {
#Override
public void onTick(long millisUntilFinished) {
Log.v("Log_tag", "Tick of Progress " + i + " " +
+ millisUntilFinished);
i++;
}
#Override
public void onFinish() {
i=0;
}
}.start();
}
Did you print out the value of time when it's not working? If time < SystemClock.elapsedRealtime() + 1000, then onFinish will be called without calling the onTick.
The timer works fine for starting then reseting and leaving the view, but if I start the time then leave the view and return and just hit Reset the app crashes. I know that most people would not hit reset when the timer is not started, but for idiot proofing I need a fix for this any suggestions?
public void startTimer(View view) {
final Handler handler = new Handler();
Timer ourtimer = new Timer();
timerTask = new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
int sec = n % 60;
int min = n / 60;
TextView timer = (TextView) findViewById(R.id.androidtimer);
timer.setText("" + String.format("%02d", min) + ":"
+ String.format("%02d", sec));
// timer.setText(n + " Seconds");
n++;
}
});
}
};
ourtimer.schedule(timerTask, 0, 1000);
}
public void stopTimer(View view) {
timerTask.cancel();
TextView timer = (TextView) findViewById(R.id.androidtimer);
timer.setText("--:--");
timerTask = null;
n = 0;
}
I think your problem is that timerTask is null as long as you do not start the timer.
So a simple if clause might help. If that's not the problem please post the exception.
public void stopTimer(View view) {
if(timerTask != null) {
timerTask.cancel();
}
TextView timer = (TextView) findViewById(R.id.androidtimer);
timer.setText("--:--");
timerTask = null;
n = 0;
}
I know this sort of question exists but I'm confused here. I'm using this code:
public class NewWaitAppActivity extends Activity {
private Handler mHandler;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mHandler = new Handler();
lcmgr = (LocationManager)this.getSystemService(Context.LOCATION_SERVICE);
Thread LocThread = new Thread(mLocationUpdater);
Log.d("TAG","About to start worker thread");
LocThread.start();
}
public void startTimer(View v) {
if (mStartTime == 0L) {
mStartTime = System.currentTimeMillis();
mHandler.removeCallbacks(mUpdateTimeTask);
mHandler.postDelayed(mUpdateTimeTask, 100);
}
}
private Runnable mUpdateTimeTask = new Runnable() {
public void run() {
final long start = mStartTime;
long millis = System.currentTimeMillis() - start;
int seconds = (int) (millis / 1000);
int minutes = seconds / 60;
seconds = seconds % 60;
TextView timer = (TextView) findViewById(R.id.time_elapsed);
if (seconds < 10) {
timer.setText("" + minutes + ":0" + seconds);
} else {
timer.setText("" + minutes + ":" + seconds);
}
mHandler.postDelayed(this, 1000);
}
};
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
// Called when a new location is found by the network location provider.
mStopTimer();
}
};
private Runnable mLocationUpdater = new Runnable(){
public void run(){
Log.d("TAG","Inside worker thread");
lcmgr.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
}
};
}
I am basically trying to stop the timer of the main thread when a location updates. The application doesn't even start, it gives the error mentioned above during runtime. The error is due to requestLocationUpdates(). It seems like I can't call stopTimer() inside onLocationChanged(). How can I correct this?
No need to even write a complicated solution:
locationManager.requestLocationUpdates(provider, 5000, 0, mylistener, Looper.getMainLooper());
This will work just fine.
whats the need of calling "lcmgr.requestLocationUpdates(....)" from the thread you created, when it is itself an asynchronous callback based mechanism?Just move this code in the onCreate() of your activity and things should work fine.Also this error comes when you try to create a handler inside a thread which is not intended to loop at all (ie. the threads that dont call Looper.prepare, as your stack trace states also). More explanation about this error can be found in this site also.But a good explanation is also given here. http://www.aviyehuda.com/2010/12/android-multithreading-in-a-ui-environment/
You can't access/generate Event thread specific events, and you don't need to request location updates in a thread, instead you can use service to achieve the same.