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.
Related
I have a Service that shows a toast every 10s, but I'd expect Doze to slow it to every 15 minutes when it's in the background as the app is not whitelisted. Here's my service:
#Override
public void onCreate() {
super.onCreate();
if (mTimer != null)
mTimer = null;
// Create new Timer
mTimer = new Timer();
// Required to Schedule DisplayToastTimerTask for repeated execution with an interval of `2 min`
mTimer.scheduleAtFixedRate(new DisplayToastTimerTask(), TIMER_DELAY, TIMER_INTERVAL);
}
...
private class DisplayToastTimerTask extends TimerTask {
#Override
public void run() {
mHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), "Hello world", Toast.LENGTH_SHORT).show();
}
});
}
}
What I'm getting in the emulator is that the toast is shown every 10s even when I'm at the home screen. Doesn't Doze restrict all non-whitelisted background services/apps to 15 min waking time?
Doze occurs only when the screen is off, and has been for some minimum amount of time. It has nothing to do with just backgrounding.
In addition, Timers or Threads set by the service wouldn't automatically be canceled, as 1)the OS doesn't know about them and 2)There's no way to know if its safe to do so, or if doing so would cause deadlock or other errors. They may be delayed to the Doze allowed rate of execution, but would not be stopped.
i build app which give Location update to server in background using service and broadcastreceiver.i put timer(Run every X Minute) which run method of location.it include fatch lattitude,longitude and update to server with API Call.
I have a problem and quastions . there is a list of this.
1.my timer goes sleep when device is in standby mode or sleep mode
2.i have to update location if user last location and current location distance 500m or greater.
3.I want to know how much minute or second tack device for going sleep mode?
4.my timer run perfactly in running devoce mode than why stop or sleep in device sleep mode?
my timertask
class TimeDisplayTimerTask extends TimerTask {
#Override
public void run() {
// run on another thread
mHandler.post(new Runnable() {
#Override
public void run() {
location();
notifyUser2();
Log.d("timeeeeeeee22222222", "time22222222");
// display toast
}
});
}
//in oncreate
if (mTimer != null) {
mTimer.cancel();
} else {
// recreate new
mTimer = new Timer();
}
// schedule task
mTimer.scheduleAtFixedRate(new TimeDisplayTimerTask(), 0, NOTIFY_INTERVAL);
Is the currect Way to timer run? if yes than Why it Sleep while device in standby mode or sleep mode?
Help me i searched lots of sites but can't get it.
Thanks in advance
i currently work on an app that needs a lot of battery in order to support background gps tracking. my experience shows that people just forget about the app runnning in the background when they dont really need the tracking anymore. therefore i setup some code that should close the application after 4 hours.
public class SelfDestructor {
private static SelfDestructor instance;
private final long IDLE_TIME_UNTIL_AUTO_DESTRUCT = 4 * 60 * 60 * 1000; // 4 hours
private Handler handler;
private Runnable closeApp = new Runnable() {
#Override
public void run() {
System.exit(0);
}
};
public static SelfDestructor getInstance() {
if (SelfDestructor.instance == null) {
SelfDestructor.instance = new SelfDestructor();
}
return SelfDestructor.instance;
}
public void keepAlive() {
if (handler == null) {
handler = new Handler();
}
handler.removeCallbacks(closeApp);
handler.postDelayed(closeApp, IDLE_TIME_UNTIL_AUTO_DESTRUCT);
}
}
now in my main activity i call keepAlive().
#Override
protected void onResume() {
super.onResume();
SelfDestructor.getInstance().keepAlive();
}
#Override
protected void onStart() {
super.onStart();
SelfDestructor.getInstance().keepAlive();
}
now if i set the time to an hours or so and debug the that functionality everything works fine. if i set the time to 4 hours the System.exit(0); is never called. i am assuming the app thread with the close callback is just put on hold by the android system after a while and therefore will not be executed anymore while gps will continue to run. any ideas how to properly get this to work?
handler and postDelayed are not suited for long timers. At most they should be used within a few seconds and personally I think I never used one for anything more than 2 seconds.
Said all that, Android have an appropriate class for "stuff that should happen after a long time", it's called AlarmManager: http://developer.android.com/reference/android/app/AlarmManager.html
you can get the references to the system service AlarmManager by calling Context.getSystemService(Context.ALARM_SERVICE)
and then set it by calling am.set(AlarmManager.ELAPSED_REALTIME, IDLE_TIME_UNTIL_AUTO_DESTRUCT, operation)
the operation is a PendingIntent to a BroadcastReceiver that you register in the AndroidManifest.xml via the <receiver> tag. Then you do the close application code inside this broadcast receiver.
Also I should add that it's NEVER good to call System.exit(0);, as this just destroy the VM without much of a warning. It's a better, more organised/structured shut down if you pass a command to the Service that is holding the GPS (I believe you're running a service), then this service will cancel the GPS request, and call stopSelf();
I'm developing an Android app that needs to do some updating in the background every hour or so. I have a background service which I've made Sticky. And I'm using Timer.scheduleAtFixedRate to schedule the updates.
This seems to work fine. But I've noticed that when I close the app, the next time the scheduled update runs, it causes Application.onCreate to get called again.
This is a problem because Application.onCreate is where I'm grabbing data down from APIs ready to display to the user. I don't want this to happen in the background.
Is this expected behaviour? If so, perhaps I need to add a check in onCreate to see if the app is in the foreground first? Or maybe I've got something set up wrong?
Thanks!
p.s. It's a Galaxy Samsung running Jelly Bean 4.2.1
Background Service code:
#EService
public class BackgroundService extends Service {
...
private Timer timer = new Timer();
private void performUpdate() {
// Do the stuff here that we need to do on a schedule...
Log.i(LOG_CONTEXT, "Perform scheduled update");
...
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(LOG_CONTEXT, "Background thread started");
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
performUpdate();
}
}, 0, UPDATE_INTERVAL);
// Sticky means service will continue running until explicitly stopped
return START_STICKY;
}
#Override
public void onDestroy() {
Log.d(LOG_CONTEXT, "Background thread stopped");
timer.cancel();
}
}
Application code:
#EApplication
public class MyApplication extends Application {
...
#Override
public void onCreate() {
super.onCreate();
initApp();
}
private void initApp() {
// This is where I want to do stuff when the app is actually
// opened by the user, not every time the background service
// update occurs!
Log.i(LOG_CONTEXT, "Initialise. Why does this happen again after app's closed?");
...
}
...
Log:
12-09 16:28:15.828: I/MyApplication(3049): Initialise. Why does this happen again after app's closed?
[Now I close the app, by pressing the Recent Apps menu button and swiping it away]
12-09 16:28:16.015: I/BackgroundService(3049): Perform scheduled update
12-09 16:28:33.875: I/MyApplication(3080): Initialise. Why does this happen again after app's closed?
Your service runs as a part of your application, so the application is created for it.
Most apps do not need to extend Application. Without seeing all of your code, I'm pretty sure you don't need to either. Just extend Activity for the class that displays stuff to the user and do the API stuff in that. That will not be created when the service runs.
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.