I am using FIREBASE DATABASE and I want to add A countdown timer to be shown to all users at the same time.
How to perform that in a very simple way?
My database is like this:
time:"9000" //which represent the 9 seconds
`
I tried to do something like this but it only retrieves the beginning of the time with no update of time of the database.
the overall idea is that I want every user to see the same time when he enters the activity
value= FirebaseDatabase.getInstance().getReference().child("time");
value.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
long v= (long) dataSnapshot.getValue();
CountDownTimer countDownTimer=new CountDownTimer(v,1000) {
#Override
public void onTick(long millisUntilFinished) {
show.setText("time : "+millisUntilFinished/1000);
}
#Override
public void onFinish() {
Intent i=new Intent(Main4Activity.this,OneActivity.class);
startActivity(i);
}
}.start();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
This might/might not be what you want, as it depends on a few factors. (especially cost)
You can have firebase-functions be your timer but it has a maximum execution time of 540 seconds, and after a certain quota, are not free.
https://cloud.google.com/functions/pricing
If you have a structure like this:
root
- connectedUsers
- userUid:true
- time: <time> // put your time in ms here
- observedTime: 0
- startTimer
then you will need to do a few things:
1: in onStart() / onStop() of your Activity, set/delete your user from connectedUsers via ref.child('connectedUsers').child(FirebaseAuth.getInstance().getCurrentUser().getUid()).setValue(true/null);
2: create 2 function triggers (pseudo-code)
exports.connectedUsers = functions.database.ref('/connectedUsers/{userId}').onWrite((event) => {
// return db.child('connectedUsers').get() as promise
// then check the childCount
// if it's 5, return db.child('startTimer').set(true);
// otherwise return 0
});
exports.timerFunction = functions.database.ref('/startTimer/').onWrite((event) => {
// start a timer, make sure it's a promise
// on each interval (seconds) call(not return) db.child('observedTime').set(timeLeft);
// after timer is done, return promise
// then return db.child('startTimer').delete();
});
3: inside your Activity onStart also add a ValueEventListener pointing to ref.child("observedTime") and set your Text with (don't forget to parse as string)
That's about it, as soon as 5 people are connected the function connectedUsers will trigger the timerFunction, which will start a timer and updating observedTime each interval, after that it will delete the triggerRequest.
Note, if one client loses connection, their timer will stop. There are more edge cases you would need to handle (what if a 6th client connects? or one leaves?)
If you don't want to use functions to do the countdown, you can of course have the client updating it, but that adds complexity (who updates the timer?)
Another solution could be that all users have their local timer on their phone, listen on the 'startTimer' node, and when it comes in they start their countdown. Someone(functions/client) would still need to post that request for everyone to observe, and clients might not be 100% sync
#Override
protected void onStart() {
super.onStart();
//fetch test time in minutes
//and convert that into milli seconds
mTimerRef = FirebaseDatabase.getInstance().getReference("eTest").child(key).child("TestMinutes");
mTimerRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
mTimeLeftInMillis = (Integer.parseInt(dataSnapshot.getValue(String.class))) * 6000;
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException();
}
});
mCountDownTimer = new CountDownTimer(mTimeLeftInMillis,1000) {
#Override
public void onTick(long millisUntilFinished) {
mTimeLeftInMillis = millisUntilFinished;
updateCountDownText();
}
#Override
public void onFinish() {
mTimerRunning = false;
//when timer will finish
//submit marks to firebase and close this activity
//once marks is been submitted to firebase then close the quiz
FirebaseDatabase.getInstance().getReference("eTest").child(key).child("Marks").child(sIdHeader).setValue(Integer.toString(mScore));
Intent intent = new Intent(QnA_Test_Activity.this, Attempt_eTest_Activity.class);
startActivity(intent);
finish();
QnA_Test_Activity.this.finish();
}
}.start();
mTimerRunning = true;
}
private void updateCountDownText(){
int minutes = (int) (mTimeLeftInMillis / 1000) / 60;
int seconds = (int) (mTimeLeftInMillis / 1000) % 60;
String timeLeftFormatted = String.format(Locale.getDefault(),"%02d:%02d",minutes,seconds);
mQnATimer.setText(timeLeftFormatted);
}
I hope this will help you,
just set minutes in firebase and this code will fetch minutes and convert them into millis and then implement timer.
Related
Here,I have all the the id of record store in database in arraylist.My main point is How to Keep that Record For Some Seconds and then proceed further .
public class AuctionStart extends AppCompatActivity {
ArrayList<String> arr;
TextView tv;
int i;
DatabaseReference drf;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_auction_start);
tv = (TextView) findViewById(R.id.aucnm);
Bundle b = getIntent().getExtras();
if (null != b) {
arr = b.getStringArrayList("list");
}
else {
Toast.makeText(this, "Sorryy", Toast.LENGTH_SHORT).show();
}
}
}
after this suppose display arraylist first element in textview for 3 seconds then simultaneously all.
It's simple and straight forward. You can use postDelayed(). Here is the code snippet may help you, to achieve setTimeout() like thing,
new android.os.Handler().postDelayed(
new Runnable() {
public void run() {
// This will executed after 3 seconds
// Your Logic here
}
},
3000);
and here is the code snippet can help you to run on interval like setInterval
new Timer().scheduleAtFixedRate(new TimerTask(){
#Override
public void run(){
//This will execute after every 5 second untill timer cancel()
}
},0,5000);
For your case, you can do it as given,
if (null != b) {
arr = b.getStringArrayList("list");
int index = 0;
Timer t = new Timer();
t.scheduleAtFixedRate(new TimerTask(){
#Override
public void run(){
tv.setText(arr.get(index));
if(index == (arr.size() - 1)){
t.cancel();
}else{
index++;
}
}
},0,3000);
}
else {
Toast.makeText(this, "Sorryy", Toast.LENGTH_SHORT).show();
}
Use rx java and rxfirebase and there is function in rx java will repeat the process again but I don’t recommend that you can eather use cloud function and add background service on firebase cloud to togle a key to update your data since it’s real time it will auto refresh and btw you need to make sure about both of the movements will cost you money 🤪
I have count down timer which is display by ProgressBar and successfully. But unfortunately there is problems.
The progressBar Start in 1/5 instead 0/5. and Stuck 2 seconds in 4/5 progress
If I recall the Function of Count down Timer before
public void onFinish() {
progresBar.setProgress(100);
}
display will be mess up for a while.
I really miss Unity Engine with Time.deltaTime;
Here is my code:
countDownTimer2 = new CountDownTimer(5000,1000) {
int i = 0;
#Override
public void onTick(long milliSecondUntilFinished) {
i++;
progresBar.setProgress((int) i * 100 / (5000/1000));
}
#Override
public void onFinish() {
progresBar.setProgress(100);
}
}.start();
You are incrementing your i variable before setting your progress. When onTick() is called for the first time, the value of i is 1. Thus progress you are setting is 20 which is equivalent to 1/5. Use this -
#Override
public void onTick(long milliSecondUntilFinished) {
progresBar.setProgress((int) i * 100 / (5000/1000));
i++;
}
Also, you should better use milliSecondUntilFinished to find progress instead of unneccesarily introducing i variable.
For the problem with the display, I highly doubt that you have not canceled the timer already running before calling a new one. If yes, then both timer would be running until older one finishes (till this point, the progress bar will be behaving weirdly).
You can cancel the previous timer as -
countDownTimer2.cancel();
Do this before starting a new one.
Using:
countDownTimer2 = new CountDownTimer(1000,5000) {
int i = 0;
#Override
public void onTick(long milliSecondUntilFinished) {
i++;
progresBar.setProgress((int) i * 100 / (5000/1000));
}
#Override
public void onFinish() {
progresBar.setProgress(100);
}
}.start();
I am having a problem repeating countdown timer multiple times,in my case 12 times. I have made two countdown timers,one for roundtime and one for pause and works great.Problem is when the pause is finihed I want that roundtime countdown starts again automaticly until 12 rounds with pause are finished.
I use for loop.Is there any better way?
Here is code: when user clicks the button countdown starts
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
long roundtime= Long.parseLong(String.valueOf(msg1))*1000;//user has picked roundtime
Counting timer = new Counting(roundtime, 100);//class Counting extends CountdownTimer
for(int i=0;i<12;i++){
timer.start(); // It goes just ones!
}
}
And countdown timer:
class Counting extends CountDownTimer {
public Counting(long roundtime, long countDownInterval) {
super(roundtime, countDownInterval);
}
#Override
public void onTick(long millisUntilFinished) {
textView.setText("" + String.format("%02d:%02d",
TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished) - TimeUnit.HOURS.toMinutes(
TimeUnit.MILLISECONDS.toHours(millisUntilFinished)),
TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) - TimeUnit.MINUTES.toSeconds(
TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished))));
}
#Override
public void onFinish() { // When roundtime is finished,start pause time!
int seconds = msg1 % 60;
int minutes = (msg1 / 60) % 60;
textView.setText(String.format("%02d : %02d", minutes, seconds));
long pause= Long.parseLong(String.valueOf(msg2))*1000; //user has picked pause time
Counting2 timer2 = new Counting2(pause, 100);
timer2.start();
}
}
class Counting2 extends CountDownTimer {
public Counting2(long pause, long countDownInterval) {
super(pause, countDownInterval);
}
#Override
public void onTick(long millisUntilFinished) {
textView2.setText("" + String.format("%02d:%02d",
TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished) - TimeUnit.HOURS.toMinutes(
TimeUnit.MILLISECONDS.toHours(millisUntilFinished)),
TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) - TimeUnit.MINUTES.toSeconds(
TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished))));
}
#Override
public void onFinish() {
int seconds = msg2 % 60;
int minutes = (msg2 / 60) % 60;
textView2.setText(String.format("%02d : %02d", minutes, seconds));
}
}
});
}
First off, you want it to loop 12 times.
This isn't the issue at hand, however, you'll thank me when it only loops 11 times.
it should be
for(int i=0;i<=12;i++){
timer.start(); // It goes just ones!
}
As I do not know the implementation of Counting2, it appears to be getting hung up on the start function there. I do not know if it's overridden or not. If you have a similar onFinish method, this is due to a recursive call back on the original Counting timer. Because of this, it loops with a waiting period in between (It doesn't get a stack overflow 'as quickly' as a result).
Try busy waiting for the previous timer to finish and then start it again, and it'll do so 12 times.
for(int i=0;i<12;i++){
while(!previousTimerActive);
timer.start();
previousTimerActive = true;
}
And in your Counting2's onFinish() set the indicator previousTimerActive = false;. Now you just need to see what way you want this boolean previousTimerActive to be 'global' (so it can be accessed from both your activity and your class Counting2). You can get it and set it in the SharedPreferences or use a third-party tool like EventBus to send it's value from one to the other.
I'm making simple android app which should have counter which counts from 60 seconds down to 0 seconds. I have one idea how to do it, but I'm not sure if it is the smartest way to do it. And I'm not sure how to make it work in the code.
Idea:
In the .xml file I have added textView. I would make MyService class that extends Service which will be called by the .java file inside OnCreate function (because I want that counting starts immediately). MyService will change content of textView every second (I will have int counter which will be decreased every second and then text of textView will be changed).
Is there any better way to do it?
Here is MyService class:
public class MyService extends Service {
//for timer:
int counter = 0;
static final int UPDATE_INTERVAL = 1000;
private Timer timer = new Timer();
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
doSomethingRepeatedly();
return START_STICKY;
}
private void doSomethingRepeatedly() {
timer.scheduleAtFixedRate( new TimerTask() {
public void run() {
//code for changing the content
}
}, 0, UPDATE_INTERVAL);
}
#Override
public void onDestroy() {
super.onDestroy();
//za timer
if (timer != null){
timer.cancel();
}
}
}
Do I have to put this code in separate .java file?
I'm not sure how to write code for changing the content of textView, because I'm not sure if I can call id of textView because it is in the separated file?
These would be functions for starting the Services:
public void startService(View view) {
startService(new Intent(getBaseContext(), MyService.class));
}
public void stopService(View view) {
stopService(new Intent(getBaseContext(), MyService.class));
}
Where do I have to put them?
Use a CountDownTimer.
Schedule a countdown until a time in the future, with regular
notifications on intervals along the way. Example of showing a 30
second countdown in a text field:
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
mTextField.setText("done!");
}
}.start();
The calls to onTick(long) are synchronized to this object so that one
call to onTick(long) won't ever occur before the previous callback is
complete. This is only relevant when the implementation of
onTick(long) takes an amount of time to execute that is significant
compared to the countdown interval.
Before I start I have looked at lots of threads including:
How to add time to countdown timer?
Android game countdown timer
But I just cant get my timer to work in the way I require. I want the timer to be counting down from say 30 and when and image is pressed (named imageview1 in this case) the timer adds 3 seconds to the timer to give it more time. I know you cannot essentially add the time while its running and you need to cancel and then start a new timer, The code I have so far is :
public void onClick(View v) {
// TODO Auto-generated method stub
//GlobalClass global = new GlobalClass();
Random rand = new Random();
CountDownTimer thetimer = new myTimer(millisInFuture, 1000);
switch(v.getId()) {
case R.id.buttonstart:
btnstart.setVisibility(View.INVISIBLE);
thetimer.start();
break;
case R.id.imageView1:
if (thetimer != null){
thetimer.cancel();
thetimer = new myTimer(countdownPeriod + 3000, 1000).start();
}
break;
with lots of other case references then :
public class myTimer extends CountDownTimer {
public myTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
#Override
public void onTick(long millisUntilFinished) {
timedisplay.setText("Time Left: " + millisUntilFinished / 1000);
countdownPeriod=millisUntilFinished;
}
#Override
public void onFinish() {
timedisplay.setText("Timer Finished");
started = false;
btnstart.setVisibility(View.VISIBLE);
}
}
I think the problem is its not cancelling the original timer so the label that shows the timer does some crazy things, like jumping around on different numbers both up and down as there would appear more than 1 class of thetimer. That is even though I have included the line thetimer.cancel(); The timer works fine if I just let it run to 0.
Any help would be great
You should not create your timer as a local in onClick. Instead create it as a global and start it somewhere else (in onCreate perhaps).
What happens with your current code is that whenever onClick is called a new timer is created and you then cancel the new timer - which has no effect on any previously created timer(s).
Try something like this:
public class MyActivity extends Activity {
CountDownTimer thetimer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
thetimer = new myTimer(millisInFuture, 1000);
}
public void onClick(View v) {
Random rand = new Random();
switch(v.getId()) {
case R.id.buttonstart:
btnstart.setVisibility(View.INVISIBLE);
thetimer.start();
break;
case R.id.imageView1:
if (thetimer != null) {
thetimer.cancel();
thetimer = new myTimer(countdownPeriod + 3000, 1000).start();
}
break;
}
}
}
You will still have to keep track of the global time somewhere - i.e. the countDonwPeriod used to re-create the timer instance when an image is touched - it should probably be extracted from the timer before canceling it.