Need to create stopwatch in android, for now I'v got somethink like this, simple function to start counting and display time, but i dont know what am I doing wrong with postdelayed:
fun runTimer() {
val timeView = findViewById<TextView>(R.id.time_view)
val handler = Handler()
handler.post(Runnable {
var hours = seconds / 3600
var minutes = (seconds % 3600) / 60
var secs = seconds % 60
var time = String.format("%d:%02d:%02d", hours, minutes, secs)
timeView.setText(time)
if (running) {
seconds++
}
handler.postDelayed(this, 1000)
})
}
what exactly should i put instead of this? (need to be runnable type)
I believe in your use case the most suitable solution would be to use a Chronometer - you can read more about it here. Also if you want to watch a video tutorial you can check this video. Hope this helps. Additionally if you want to have the functionality to be able to set a specific time frame and countdown using a CountDownTimer is a good option - documentation
I use handler as Timer like this :
class TimerClass {
fun startTimer( handler : Handler ,
stuffToDo : () -> Unit ,
stopTimeInSeconds : Int ,
timePassed : Int ,
interval : Long){
handler.postDelayed( {
stuffToDo.invoke()
if (timePassed < stopTimeInSeconds){
startTimer(handler ,
stuffToDo ,
stopTimeInSeconds ,
timePassed + 1 ,
interval)
}
} , interval)
}}
then to use it :
val time = TestClass()
time.startTimer(handler = Handler() ,
stuffToDo = { textView.text = "some new text" } ,
stopTimeInSeconds = 5 ,
timePassed = 0 ,
interval = 1000)
So you define a method in the class , and provide all dependencies(objects) and injecting to it, you are creating the operation you want to do as a lambda function. then call the handler delayed method and in the handler if the criteria (if statement) is true you will call the method itself recursively with an increment (timePassed+1).
Now you have a working timer.
Related
Hello everyone I'm trying to make a small timer that will display how many minutes and seconds are left until a certain time. I want to do this using the difference between the present time and the time to which the countdown is running, but I can't figure out how to do it.
It is necessary to output the time in the format "hh:mm". That is, if now, for example, "13:27:28", and the desired time is "14:00:00", then the final result should be "32:32". And is it possible to compare time somehow? Check whether the present time is greater or less than the specified one.
import java.time.LocalTime
import java.time.format.DateTimeFormatter
fun main(args: Array<String>) {
println(calculateTime("13:27:28", "14:00:00"))
}
private fun calculateTime(from: String, to: String): String {
val formatter = DateTimeFormatter.ofPattern("hh:mm:ss")
val time1 = LocalTime.parse(from, formatter)
val time2 = LocalTime.parse(to, formatter)
return time1.toString() + time2.toString()
}
Try Stopwatch from Apache Commons
val stopWatch = StopWatch().apply { start() }
...
stopWatch.stop()
println("Completed after $stopWatch")
and you get something like this: "Completed after 00:00:18.832"
I have in a DB 10 stored speeds, which I want to show in a speedview, but when I run the app only the last speed is shown. I have tried to put a Handler so that in each repetition of the loop it takes a few seconds to execute and thus to be able to show each speed, but the result is always the same (only the last speed is shown).
private fun cambiarVelocidad() {
var speedometer = findViewById<SpeedView>(R.id.speedView)
var querys = db.vehiculoDao()
var todasVelocidades = querys.getTodasVelocidades()
var contador = 1
for (i in todasVelocidades){
var velocidadActual = querys.getVelocidadById(contador)
speedometer.speedTo(velocidadActual.toFloat())
if(velocidadActual != null){
contador++
Handler(Looper.getMainLooper()).postDelayed(
{
speedometer.speedTo(velocidadActual.toFloat())
cambiarCuentarrevoluciones(speedometer.speed.toInt())
},
3000 // value in milliseconds
)
}
}
}
dfdf
So currently I am making a Pokédex for my internship.
I've got it working for the biggest part but there's a couple of things I need to get fixed including the question asked above.
I have a function called Eeveelutions which has to run three other functions called showVaporeon, showJolteon & showFlareon. They have to run for like 3 seconds each and then just loop around until the person using the pokedex goes to the next or previous pokémon.
The thing I need help with is how would I set a timer, (if that's the best way to do it) to run those functions. So, showVaporeon for 3 seconds, then showJolteon for 3 seconds, then Flareon for 3 seconds and repeat.
I have searched loads of questions to find my solution but I can't find it yet and most of it is not in kotlin.
So, is there anyone who has got an easy example for me or a better solution (and example) then using a timer.
Searched forum for solutions,
messed around with timers,
messed around with threads but no solutions yet
fun showVaporeon(){
evoChart2.visibility = View.VISIBLE
Glide.with(this).load(imageBaseURL + "134" + ".png").into(evoChart2)
evolveOption2.text = "Vaporeon"
evolveOption2.text = ""
evoChart2.visibility = View.GONE
}
fun showJolteon(){
evoChart2.visibility = View.VISIBLE
Glide.with(this).load(imageBaseURL + "135" + ".png").into(evoChart2)
evolveOption2.text = "Jolteon"
evolveOption2.text = ""
evoChart2.visibility = View.GONE
}
fun showFlareon(){
evoChart2.visibility = View.VISIBLE
Glide.with(this).load(imageBaseURL + "136" + ".png").into(evoChart2)
evolveOption2.text = "Flareon"
evolveOption2.text = ""
evoChart2.visibility = View.GONE
}
So I would want evoChart2 (which is one of the three imageviews I have) to show Vaporeon for 3 seconds, then Jolteon for 3 seconds, then Flareon for 3 seconds, and then Vaporeon again for 3 seconds, Jolteon, Flareon etc.
Since you're wanting a loop, I'd suggest using a list to make it easier to iterate and add more pokemon in future.
Create a Pokemon data class if you don't have one already.
data class Pokemon(val name: String, val imageUrl: String)
Create however many instances of this class as you need and add them to a list.
val pokemonList: List<Pokemon> = listOf(vaporeon, jolteon, flareon)
We'll also need to store the index of the current pokemon we're displaying
var currentIndex = 0
Next we'll create a Runnable and schedule it to execute every three seconds, you may want to do this in onResume.
val service = Executors.newSingleThreadScheduledExecutor()
service.scheduleAtFixedRate({ displayPokemon() }, 0, 3, TimeUnit.SECONDS)
Now create the displayPokemon function that is going to be called every 3 seconds.
fun displayPokemon() {
}
Inside this function we need to know what the next pokemon we're displaying is, based on the current pokemon.
val next = currentIndex + 1
if (next >= pokemonList.size) {
// we're at the end, go back to 0
currentIndex = 0
} else {
currentIndex = next
}
val pokemon = pokemonList[currentIndex]
Now that we have the next pokemon to display we can use it to populate the view
evoChart2.visibility = View.VISIBLE
Glide.with(this).load(pokemon.imageUrl).into(evoChart2)
evolveOption2.text = pokemon.name
evolveOption2.text = ""
evoChart2.visibility = View.GONE
Finally, we don't want this to happen when the Activity/Fragment is in the background so we add the following code to onPause
service.shutdown()
On Android there exists a standard view called Chronometer details here. Does iOS have a similar view or a library that does something similar?
I not found anyway todo this, so i create a gist here with GPL license, if someone get excited to make it a lib :)
I would use an Timer for this.
var timer = Timer()
timer = Timer(timeInterval: 0.01, target: self, selector: #selector(update), userInfo: nil, repeats: false)
#IBAction func start(sender: UIButton) {
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(ViewController.update(_:)), userInfo: nil, repeats: true)
RunLoop.current.add(timer, forMode: RunLoop.Mode.common)
startTime = Date() // new instance variable that you would need to add.
}
func update() {
let elapsedTime = Date().timeIntervalSince(startTime)
let currTime = totalTime - elapsedTime
//total time is an instance variable that is the total amount of time in seconds that you want
countDown.text = String(currTime)
if currTime < 0 {
timer.invalidate()
//do other stuff that you need to do when time runs out.
}
}
If you want a smaller or larger pieces of time, just change it the Interval parameter.
Also you still would have to address creating some logic to split minutes / seconds ect. using Date methods and incrementing some instance variable.
Why not use a UIDatePicker in timer mode?
UIDatePicker* datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 0, 320, 206)];
datePicker.datePickerMode = UIDatePickerModeCountDownTimer;
datePicker.countDownDuration = 60*5;
[self.view addSubview:datePicker];
I would like to start a task at a specific time. For that I use runnable and postDelayed method as follows:
private Runnable mLaunchTask = new Runnable() {
public void run() {
try {
MY TASK
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
};
In my code I use mLunchTask as follows:
mHandler = new Handler();
mHandler.postDelayed(mLaunchTask, myDelay*1000);
and myDelay is computed as follows:
s = DateFormat.format("hh:mm:ss aaa", d.getTime());
cTime = s.toString(); // current Time
ch = Integer.parseInt(cTime.substring(0,2)); // current hour
cm = Integer.parseInt(cTime.substring(3,5)); // current minute
cs = Integer.parseInt(cTime.substring(6,8)); // current second
if (cTime.substring(9,11).equalsIgnoreCase("pm") && (ch<12) ) ch = ch+12;
myDelay=(desiredHour-ch)*3600+(desiredMinute-cm)*60 - cs;
if (myDelay<0) myDelay = 0;
and desiredHour and desiredMinute are set by user. The expectation is that MY TASK starts at desiredHour and desiredMinute and 0 seconds.
However "MY TASK starts with a few seconds delay, which looks like is random.
Based on the above code, is there any reason that it does not start at the exact desired time?
Thanks
First of all, your delay calculation is correct, but the "pm" detection doesn't work with other languages. It is much better to use the calendar to get the delay:
Calendar calendar = Calendar.getInstance();
long currentTimestamp = calendar.getTimeInMillis();
calendar.set(Calendar.HOUR_OF_DAY, desiredHour);
calendar.set(Calendar.MINUTE, desiredMinute);
calendar.set(Calendar.SECOND, 0);
long diffTimestamp = calendar.getTimeInMillis() - currentTimestamp;
long myDelay = (diffTimestamp < 0 ? 0 : diffTimestamp);
Now you have the delay in milli secs and can start the handler:
new Handler().postDelayed(mLaunchTask, myDelay);
In my test the following runnable logs at the desired time with no delay.
private Runnable mLaunchTask = new Runnable() {
public void run() {
Calendar calendar = Calendar.getInstance();
Log.d("test", "started at "
+ calendar.get(Calendar.HOUR_OF_DAY) + " "
+ calendar.get(Calendar.MINUTE) + " "
+ calendar.get(Calendar.SECOND)
);
}
};
Maybe your started task needs some seconds to be loaded?
Could the AlarmManager be an alternative?
Based on my experience and reading of the documentation, postDelayed is based on uptime, not real time. If the phone goes into deep sleep, it can cause real time to pass without uptime incrementing. That means your task will start later than desired.
The Handler really seems to be designed for updating the GUI in an active activity, not scheduling tasks far in the future. As scessor said, AlarmManager is probably your best bet.
The Naliba's answer is not completely correct.
Based on documentation that can be seen here
it can be seen that this class is specifically used for running tasks in the future.
"There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own. "
There is no reference about the behavior of the application when the system enters in sleep mode and this issue should be tested before posting additional information.