I am creating application which works with SMS service and FTP networking.
If user does not establish connectivity, it will try to reconnect again in 30 seconds.
I am using CountDownTimer with TextView to inform user about time left to reconnnect.
Either it will be successful or it will start counting again.
My problem is, that if counter restarts while activity is in background or the screen is locked, TextView keeps showing number "1" (it won't update) until the timer restarts again in foreground (but updating numbers without timer restart works fine in backround or lock, I am using wakelock in my foreground service).
After counter restarts again (so it won't stop counting) while application is in foreground, everything comes back to normal, TextView updates from freezed "1" to "30" and starts counting down to "1".
I think problem will be somewhere in communication between counter thread and background activity with UI, but I don't know nothing more about it.
I tried several things like:
creating setter and getter for miliseconds and update them in each
tick, then try to update textview from onReume(), didn't work.
create local variable for TextView inside timer, initialize it inside onTick() and
try to update text from there, also didn't work.
Thanks everyone for help, I will appriciate any advices.
Part of code relative to question:
private CountDownTimer cdt = null;
private final TextView getTextView_ActivityMainMenu_Timer(){
return (TextView) findViewById(R.id.ActivityMainMenu_TextView_Timer);
}
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getBooleanExtra("KEY_FAILED", false)){
cdt = new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
getTextView_ActivityMainMenu_Timer().setText("" + millisUntilFinished / 1000);
}
public void onFinish() {
;
}
}
.start();
}
else
{
if(cdt != null)
cdt.cancel();
}
}
};
Finally I found solution of this problem. I didn't realize that I am unregistering the receiver in onPause() method. So I had to change it and put registration of broadcast into onResume() and unregister it only in onDestroy() method.
Related
My project is a radio app and I want to add a sleep timer so that the user can set it to close the app after a specified time.
Please use startTimer(long ms) to start countdown timer and cancel timer to stop. And use wakelock to continue timer after screen off.
CountDownTimer cTimer = null;
void startTimer(long time) {
if(!wakeLock.isHeld()) {
PowerManager mgr = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SonaHeartLock");
wakeLock.acquire();
}
cTimer = new CountDownTimer(time, 1000) {
public void onTick(long millisUntilFinished) {
timerSync = millisUntilFinished;
}
public void onFinish() {
timerSync = 0;
System.exit(0);
}
};
cTimer.start();
}
//cancel timer
void cancelTimer() {
if (cTimer != null) {
timerSync = 0;
cTimer.cancel();
cTimer=null;
if(wakeLock!=null && wakeLock.isHeld())
wakeLock.release();
}
}
Thread.sleep(2000);
will pause for 2 seconds (i.e 2000 ms). In an Android app I wrote several years ago I actually had:
Thread.currentThread().sleep(2000);
but I'm pretty sure the .currentThread() was not needed. I was just learning Java at the time.
See Oracle's doc.
In more detail, what I actually had was a separate task:
class TimerUpdater extends AsyncTask<String, String, Void>{
}
That periodically checked the time (pausing using Thread.sleep()) and displayed a countdown, and at zero set a flag that the main task periodically checked and ended the game when it saw it was set.
My app was terrible code, but I was learning both Java and Android at the same time as fast as I could, to make an app to help my kid in math class.
Android has changed a lot since then, though.
You can get the time from user and after that you can create one background process which count time everytime and check with user time. If both will match then immediately close your app
I want to logout users after they have been inactive for 3 minutes on my app i.e doing nothing for 3 minutes. I have only one Activity and it contains multiple Fragments. How can I achieve this? I tried the answers posted on the same topic but nothing worked. Please can anyone be specific?
Each Activity has an onUserInteraction() function. You can override it and reset a Runnable. If there is no user interaction the Runnable will be called after 3 minutes. Don't forget to remove Runnable onDestory().
Runnable r = new Runnable() {
#Override
public void run() {
// handle timeout
}
};
Handler handler = new Handler();
#Override
public void onUserInteraction() {
super.onUserInteraction();
handler.removeCallbacks(r);
handler.postDelayed(r, 3 * 60 * 1000 );
}
#Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacks(r);
}
Try this
Use CountDownTimer
CountDownTimer timer = new CountDownTimer(15 *60 * 1000, 1000) {
public void onTick(long millisUntilFinished) {
//Some code
}
public void onFinish() {
//Logout
}
};
When user has stopped any action use timer.start() and when user does the action do timer.cancel()
use alarm manager and set alarm for logout
You have two options.
Use an alarm manager and have a broadcast receiver upon receiving the alarm and log out from there. When the user does some activity, restart the alarm. example.
have a Service that you can talk to, and send intents restartTimer. When the timer reaches zero, log out the user.
Basically i'm using seek bar to show to user how audio playback is going, my visual update is presented in Thread and looks like this :
#Override
public void run() {
while(mUpdating) {
if(mSeekBar != null) {
mSeekBar.setProgress(mAudioPlaybackManager.getCurrentPosition());
}
//Other stuff is updating
}
}
So, for exqample if user plays audio that's 2500 ms in length, this SeekBar max value will be 2500 and it will be updating every ms
This same code working much slower in runOnUiThread, so i'm guessing when progress is changed something like postInvalidate is called
So basically every ms, the seekbar value should be changed. I guess that's the problem here. On my device Samsung J7 it's working smoothly but on Samsung Galaxy S5 it's just stopping and jumping all the time, like if i put this code in runOnUIThread, it would be really slow.
What could i do to make it smoother? Is there another View that i can use for this pirpose?
The things that current SeekBar is doing:
Showing progress of audio basically in while(updating)
When user changes the position of SeekBar audio is starting from that point.
The thread is a worker thread and not UI's thread, you're manipulating UI component within the thread thus blocking the UI's thread.
If you want to update the seekbar, update it in UI's thread. It can be done with UI's thread handler.
For example
private Runnable updateSeekBarTime = new Runnable() {
public void run() {
//get current position
timeElapsed = mediaPlayer.getCurrentPosition();
//set seekbar progress
seekbar.setProgress((int) timeElapsed);
//repeat yourself again in 100 miliseconds
durationHandler.postDelayed(this, 100);
}
};
Executed in
public void play(View view) {
mediaPlayer.start();
while(mUpdating) {
if(mSeekBar != null) {
// post the Runnable (updateSeekBarTime)
durationHandler.postDelayed(updateSeekBarTime, 100);
}
}
}
Also updating component can't simply be done every millisecond, from user perspective, giving a bit pause won't be noticed.
I am trying to make simple maths game. Aim of the game is to answer so many questions right in a certain time limit.
I have a timer which counts down and calls my final screen to set your highscore. Problem is, when testing the app if the back button is pressed before timer is done, it seems to continue in the background and my highScore screen randomly appears. How can I make this stop?
Here is the code for my timer:
/**
* timer method
*/
public void timer() {
new CountDownTimer(10000, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
Intent i = new Intent(MainActivity.this, HighScoreScreen.class);
i.putExtra("Score", score);
startActivity(i);
resetScore();
finish();
}
}.start();
}
One solution to this very particular problem would be to override onBackPressed and cancel your timer there. On the other hand, if you want to cancel the timer when there is any interruption (e.g. user receives a call while using your app), you could perhaps place the cancel call in a lifecycle method like onStop.
At onCreate, I run a task that repeats every minute. Here how I do it:
myTimer = new Timer();
int delay = 30000; // delay for 30 sec.
int period = 600000; // repeat every 60 sec.
doThis = new TimerTask() {
public void run() {
Log.v("TImer","repeated");
wv.reload();
}
};
myTimer.scheduleAtFixedRate(doThis, delay, period);
All that code is in onCreate. So, when the app goes off from the screen, I can see in logcat that timer steel runs, and will not stop unless the app will be destroyed. So, in onPause of activity I call myTimer.cancel(); but it didnt help. I still can see updates in logcat, even when the app is not on the screen. So, how to stop timerTask?
Here is your code put into my file, with the values delay and period tweaked so I don't have to wait so long. I run the app. I see the messages in LogCat. I press the home button on my Galaxy S3. Then the messages stop in LogCat.
public class MainActivity extends Activity {
Timer myTimer;
TimerTask doThis;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myTimer = new Timer();
int delay = 0; // delay for 30 sec.
int period = 1000; // repeat every 60 sec.
doThis = new TimerTask() {
public void run() {
Log.v("TImer","repeated");
}
};
myTimer.scheduleAtFixedRate(doThis, delay, period);
}
#Override
protected void onPause() {
myTimer.cancel();
super.onPause();
}
}
It could be that since the thread has already been sent out, it runs one last time. In the onLoad set a variable to true, then in the onPause set it to false. Then in your timer task only run your code if the variable is true.
Write to the log outside of the new if statement though. If it is indeed running it just one last time, then that might be your solution. But if it is still running it over and over multiple times after the onPause then don't take my solution.
The actual answer is: The onPause method needs to be defined correctly.
The whole story:
The questioner defined the onPause method wrong. That was the reason for asking this question.
I'm writing this because I spent too much time reading question, answers, code and comments. The real answer was hidden in the last comment.