After many trials of solutions (including posting questions on SO) I thouht will work fine. But no improvement. Coming to my problem, I am implementing an App that have a countdown timer. I am showing this on a button (Just using like a canvas by disabling the click event).
I start the timer when user clicks a button (which is a separate button). Below is the countdown timer code,
public class DigitalTimer extends Button{
--------------------------------
--------------------------------
--------------------------------
--------------------------------
--------------------------------
--------------------------------
private String timerText;
public DigitalTimer (Context context,int hourstime,int mintime,int sectime){
super(context);
Log.d(TAG,"DigiTimer constructor");
this.context = context;
initialize(hourstime,mintime,sectime,timerType);
setClickable(false);
}
public void initialize(int hourstime,int mintime,int sectime,int timerType){
Log.d(TAG,"DigiTimer initialize");
this.hourstime = hourstime;
this.mintime = mintime;
hour = hourstime;
min = mintime;
sec = sectime;
//Just Thread version
**digiThread = new Thread(){
#Override
public void run(){
while(!isPauseTimer()){
updateTimes();
SystemClock.sleep(UPDATEDELAY);
}
}
};**
//Handler version
/*
handleRunnable = new Runnable(){
public void run(){
updateTimes();
}
};
*/
}
private void updateTimes(){
timerText = String.format(timerFormat,hour,min,sec );
postInvalidate();
sec--;
if(sec < 0){
sec = 59;
min--;
}
if(min < 0){
min = 59;
hour--;
}
if(hour < 0){ //when hour is negative it means the given time completed so we stop the timer & alarm permanantely
hour = 0;
min = 0;
sec = 0;
}
}
#Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
Log.d(TAG,"DigiTimer onDraw");
setBackgroundResource(R.drawable.button9patch);
setText(timerText);
}
public void startUpdateTheread(){
//digiHandler.postDelayed(handleRunnable, UPDATEDELAY);
**digiThread.start();**
}
private void startTimersAndAlarms(){
-----------------------
-----------------------
-----------------------
-----------------------
**startUpdateTheread();**
---------------------
---------------------
}
}
Initially the timer is woking fine . But if no.of hours for the countdown is higher (say 5:00:00) then its running fine until sometime (say 4:00:00) from then it is delaying the timer update. (just to countdown a minute it is taking more time ..particularly when the user is out of the App)
First I tried with the Handler. I had the problem. I thought the delay is because of keeping the UI thread busy. So I developed a separate thread. But still the problem persist.
Sorry for the long post. Please someone point what's happening. Is that something I am missing or putting the code in wrong place?
Thanks
EDIT: I read SystemClock.sleep documentation. It says "{This clock stops when the system enters deep sleep (CPU off, display dark, device waiting for external input) }". I understand that I should keep CPU on while I run this thread. So according to the answer by #Brandon I should implement partial POWERLOCK to keep the CPU on. Is my understanding correct?
If you want to have an accurate timer, I think you'll need to get a wake lock.
Check out the documentation of PowerManager
You can either get a FULL_WAKE_LOCK to keep the screen on, or a PARTIAL_WAKE_LOCK to keep the CPU running. Don't forget to add the permission to your AndroidManifest file too.
Related
I've coded the app that check the conditions for every minute in background and if it true then it will send notification/vibrate.
It works fine, but only when my phone is active (means the screen is not locked).
I've tried many solutions like using Services, JobSchedule, WorkManager (current) but they seem not work.
The behavior of WorkManager code is like this:
(While the phone screen is locked)
min 1: send notification
min 2: send notification
min 3: nothing
min 4: nothing
......
(Turn on the screen)
Mass notifications appears, like the task is ran while locked, but only show when unlock the screen
Can anyone help me on this? I'm using OnePlus 9 Pro for testing
Code Snippet
public class MyService extends Worker {
Timer myTimer;
TimerTask doThis;
private DBHelper mydb;
public MyService(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
#Override
public Result doWork() {
StrictMode.setThreadPolicy(new Builder().permitAll().build());
mydb = new DBHelper(getApplicationContext());
// Let it continue running until it is stopped.
myTimer = new Timer();
int delay = 0; // delay for 0 sec.
int period = 1000*60; // repeat every 60 sec.
doThis = new TimerTask() {
public void run() {
//Some task
if (true) {
notify("aaaa");
Log.e("OK", "Match!");
}
...
myTimer.schedule(doThis, delay, period);
return Result.success();
}
The issue with your app is not the process but rather the android system itself.
You need to implement something called the DOZE MODE. Such that the process/ application is not killed off when the phone is locked
Google Docs On Doze Mode
There is a permission you would need to implement called the REQUEST_IGNORE_BATTERY_OPTIMIZATIONS.
I am working on a game (my first) for Android. I want a function like a lot of games do where a "consumable" regenerates over time. I want to display the countdown timer for a +1 on the consumable. When it reaches 0, i want the timer to reset and start over, while the consumable increases by 1. If the consumable is at it's pre-defined max, I want the timer to stop until the consumable is used, then systematically start again.
public class MainActivity extends Activity {
int currentConsumable = 2;
int maxConsumable = 5;
boolean isConsumableMaxed = false;
long timeToAddConsumable; //unknown calculation for 10 minutes
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView countDown = (TextView) findViewById(R.id.countDownDisplay);
if (currentConsumable==maxConsumable) {
isConsumableMaxed = true;
//some function to stop the timer
} else { isConsumableMaxed = false; }
//function to begin countdown and setText to countDown's TextView
....
}
}
What I am looking for assistance with is how to calculate the time I need (10 minutes - but i'd prefer the equation so I can change it without asking for the specific time again).
I would also like to know how to get a countdown to begin and display it on countDown, as well as how to cancel it when isConsumableMaxed == true.
Note - the countdown should continue when the game is closed.
Thanks in advance for your assistance.
I have an Android app that needs to display images and videos in a loop, it has no problem with playing the videos, but when it gets to the images the screen goes blank and nothing happens. the program is still running just not displaying.
I'm using SurfaceView.setBackground() to draw the image because swapping between an ImageView and the SurfaceView that the videos are played on has caused problems before.
I was having a similar issue when displaying the videos and I solved it by removing the loop I had waiting for the video to be prepared so ideally I would like to remove the loop I have waiting for a timer to elapse.
I have a function to display the new media when the old one is finished and it also prepares the next one for when the current one is finished. If the media is a video this is called from the onComplete function which works fine. But if it is an image I have a wait loop.
What I want to do is have something like the MediaPlayer.onComplete() function to be called when the image has been displayed for the desired amount of time. Does anything like this exist?
I have since changed this to use handlers because of some other error checking I needed to do. However the other way does work
mHandler.postdelayed(run, delay);
Runnable run = new Runnable(){
public void run()
{
//run function
}
};
I figured it out. I made a new thread that ran a timer and calls a function in the main activity that updates the screen. The call to the function that updates the screen is called using runOnUiThread() so that it has permission to change the screen.
public class ImageTimer implements Runnable{
private long dur, cur,start;
private boolean needed, run;
private Activity mAct;
ImageTimer(boolean running, long duration, Activity act)
{
run = running;
dur = duration;
needed = false;
mAct = act;
}
#Override
public void run()
{
while(run)
{
if(needed)
{
start = System.currentTimeMillis();
cur = System.currentTimeMillis() - start;
while(cur < dur)
{
cur = System.currentTimeMillis() - start;
}
needed = false ;
mAct.runOnUiThread(new Runnable()
{
public void run()
{
MainActivity.ImageDone();
}
});
}
}
}
I'm working on a presentation app, which displays different images. There I wanted to to let the presentation slide through my List of images, video and pdf files, after a short amount of time.
I start my different views through intents, startActivityForResult(intent, RESULT_OK);
Starting videos and closing videos was not an issue. I used onPreparedListener and setOnCompletionListener and everything worked like a charm.
With pictures however, this was completely diffrent.
I created a new Thread in my ImageView and did put that thread to sleep(), after that I called the setresult() method and finish(). But instead of waiting, the picture wasn't shown at all and the presentation was stuck there, without setting the result and finishing the activity.
So I started searching for some explanation of time in android and found this explanation:
Explanation
I read through it and tried to get a good grasp on whats explained there. But the more I thought about it, the more I got insecure, which is the best way to implement the waiting behavior for my intended purpose.
So instead of some code, I am much more interested in, what you would advise me to use and why with a, if possible, detailed explanation.
elapsedRealtime()?
uptimeMillis()?
System.currentTimeMillis()?
From android docs:
• System.currentTimeMillis() is the standard "wall" clock (time and date) expressing milliseconds since the epoch. The wall clock can be set by the user or the phone network (see setCurrentTimeMillis(long)), so the time may jump backwards or forwards unpredictably. This clock should only be used when correspondence with real-world dates and times is important, such as in a calendar or alarm clock application. Interval or elapsed time measurements should use a different clock. If you are using System.currentTimeMillis(), consider listening to the ACTION_TIME_TICK, ACTION_TIME_CHANGED and ACTION_TIMEZONE_CHANGED Intent broadcasts to find out when the time changes.
• uptimeMillis() is counted in milliseconds since the system was booted. This clock stops when the system enters deep sleep (CPU off, display dark, device waiting for external input), but is not affected by clock scaling, idle, or other power saving mechanisms. This is the basis for most interval timing such as Thread.sleep(millls), Object.wait(millis), and System.nanoTime(). This clock is guaranteed to be monotonic, and is suitable for interval timing when the interval does not span device sleep. Most methods that accept a timestamp value currently expect the uptimeMillis() clock.
• elapsedRealtime() and elapsedRealtimeNanos() return the time since the system was booted, and include deep sleep. This clock is guaranteed to be monotonic, and continues to tick even when the CPU is in power saving modes, so is the recommend basis for general purpose interval timing.
If the time interval, you're going to measure, is relatively short, you can use pretty much any method which gives you correct time. I prefer currentTimeMillis(). In case the time interval is really long, the recommended method is to use elapsedRealtime().
Also, if you only want to do something with a delay, simply use: http://developer.android.com/reference/android/os/Handler.html#postDelayed(java.lang.Runnable, long) . It's simple and works great.
Simplest way to achieve that is CountDownTimer
private final class CountDownTimerImpl extends CountDownTimer {
//5 sec.
private static final long TIME_INTERVAL = 5000;
private final ImageView imageView;
private final List<Drawable> images;
public CountDownTimerImpl(ImageView imageView, List<Drawable> images) {
super(TIME_INTERVAL, TIME_INTERVAL);
this.imageView = imageView;
this.images = images;
//set first image from images array to imageView
imageView.setImageDrawable(images.get(0));
}
//this method is executed after TIME_INTERVAL (5 sec.)
public void onFinish() {
//remove drawable from imageView
imageView.setImageDrawable(null);
//remove this drawable from array
images.remove(0);
//if array is not empty start another count down
if (!images.isEmpty()) {
new CountDownTimerImpl(imageView, images).start();
}
}
public void onTick(long millisUntilFinished) {
//nothing to do here
}
}
You should start this CountDownTimer by:
new CountDownTimerImpl(imageView, images).start();
where images is of course an drawables array of your presentation images.
I have no time to test this solution but it should work - if not please leave a comment and I will update it later.
You can use TimerTask
int counter=0;
final Handler handler = new Handler();
Timer ourtimer = new Timer();
TimerTask timerTask = new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
counter++;
//you can do stuffs here say like if (counter==15) { do something}
}
});
}};
ourtimer.schedule(timerTask, 0, 1000);
You can do this in a different way writing a callback module
Create a activity call it BaseActivity and let all you activities to extend it
Now declare a method call is void callback(){} keep the body empty
now in onCreate create a timer as above and call the callback function your code will look like
onCreate(){
final Handler handler = new Handler();
Timer callTimer = new Timer();
TimerTask timerTask = new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
callback();
}
});
}};
callTimer.schedule(timerTask, 0, 1000);
}
Now in you activity override the callback method which will be called after the time you specified in timer,
Ex
Class a extends BaseActivity(){
#Override
onCreate(){
// playVideo
}
#Override
void onCallBack(){
//navigate to another activity
}
}
I have an activity that runs some ASCII control over a network port to a remote device.
Every single button push on the interface will trigger an AsyncTask to handle the communication, and (finally) works great.
However, if a user starts button mashing like a chimp on crack, the system will crash with way too many calls on the same socket, so I've come up with a little timer function to slow down the reaction to their excitement.
I'm wondering if somebody has come up with a better way to do this?
First off, inside the onCreate:
btn_pwrtoggle = (Button)findViewById(R.id.pwr_btn);
btn_pwrtoggle.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(!buttonMasher){
if(powerstat.equals("OFF")){
String[] commandToSend = {"POWER","ON"}
}else{
String[] commandToSend = {"POWER","OFF"};
}
deviceControl(commandToSend);
}
startButtonMashTimer();
}else{
Log.w("button masher","slow down there, monkey.");
}
}
});
Then, in the actual Activity:
Timer buttonTimer;
TimerTask buttonMonitorThread;
int chimpCrackCounter;
protected void startButtonMashTimer() {
chimpCrackCounter = 0;
buttonTimer = new Timer();
buttonMonitorThread = new TimerTask(){
#Override
public void run(){
buttonMasher = true;
if(chimpCrackCounter == 1){
buttonMasher = false;
buttonTimer.cancel();
}
chimpCrackCounter++;
}
};
buttonTimer.schedule(buttonMonitorThread, 0, 500);
}
It seems to be working just fine, (and may help somebody having the same difficulty) but I'm open to suggestions.
An easy way to prevent a user from pushing a button too often is to save the time when a button was pushed, and then next time compare the last time with the current time and if the difference is too small, ignore the action.
final static long minTimeBetweenClicks = 1000;
long lastTime;
onClick(View v){
if( System.currentTimeMillis() < lastTime + minTimeBetweenClicks ) return;
//Handle the click
lastTime = System.currentTimeMillis();
}
The beauty of this is that it doesn't require any new threads or timers, and your AsyncTasks won't have to know about the buttons.
Disable the Button after a click (setEnabled(false), perhaps in onPreExecute, and enable after the task is done, in onPostExecute.
Also, be sure to pay attention to lifecycle changes. Your AsyncTask may be killed if the Activity is paused, so be sure to check the state in onResume.