Reputation: 287
I am creating an app that runs a 24 hour timer in the background using a handler in a Service
. The Service
should be running at all times, even when the app is fully closed. The Service
should not end until the Timer
has fully run out. Originally it was working and the Service
would continue running in the background even when the app was fully closed but all of a sudden it does not work correctly.
Here is the code for my Service
:
public class SetupTimerPC1 extends Service
{
Handler handler;
Database data;
Intent i, result;
runGraphics runG;
int bucketLevel = 1, bucketExpTotal = 0, totalWater = 0, bucketExp = 0;
float waterAmt = 0;
int timerCount = 0;
Notification notify;
Notification.Builder builder;
NotificationManager notificationManager;
PendingIntent pendingIntent;
@Override
public IBinder onBind(Intent intent)
{
return null;
}//end onBind function
@Override
public void onRebind(Intent intent)
{
super.onRebind(intent);
}//end onRebing
@Override
public boolean onUnbind(Intent intent)
{
return true;
}//end onUnbind
@Override
public void onCreate()
{
super.onCreate();
//setup 24 hour timer
handler = new Handler(Looper.getMainLooper());
handler.postDelayed(runnable, 600000); //600000 -> wait ten minutes then call runnable
}//end onCreate function
private Runnable runnable = new Runnable()
{
public void run()
{
//get current bucket exp
data = new Database(SetupTimerPC1.this);
data.open();
bucketExp = data.getBucketExp();
data.close();
//check experience for current level
if (bucketExp < 3000)
{
bucketLevel = 1;
}//end if
else if (bucketExp > 3000 && bucketExp < 6000)
{
bucketLevel = 2;
}//end else if
else if (bucketExp > 6000 && bucketExp < 9000)
{
bucketLevel = 3;
}//end else if
else if (bucketExp > 9000 && bucketExp < 12000)
{
bucketLevel = 4;
}//end else if
else if (bucketExp > 12000)
{
bucketLevel = 5;
}//end else if
//give resource based on level
if (bucketLevel == 1)
{
waterAmt += .2;
bucketExp += 1;
}//end if
else if (bucketLevel == 2)
{
waterAmt += .4;
bucketExp += 2;
}//end else if
else if (bucketLevel == 3)
{
waterAmt += .6;
bucketExp += 3;
}//end else if
else if (bucketLevel == 4)
{
waterAmt += .8;
bucketExp += 4;
}//end else if
else if (bucketLevel == 5)
{
waterAmt += 1.0;
bucketExp += 5;
}//end else if
timerCount++;
if (timerCount < 144)//144
{
handler.postDelayed(runnable, 600000); //600000
}//end if
else
{
//pull data
data = new Database(SetupTimerPC1.this);
data.open();
bucketExpTotal = data.getBucketExp();
totalWater = data.getWaterAmt();
data.close();
//add new data to old
bucketExpTotal += bucketExp;
totalWater += (int)waterAmt;
//push data
data.open();
data.bucketExpEntry(bucketExpTotal);
data.waterAmountEntry(totalWater);
data.bucketLevelEntry(bucketLevel);
data.close();
//send notification that resources have been gained
notifyUser();
i.putExtra("polarCap1Stat", true);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(i);
handler.removeCallbacks(runnable);
}//end else
}//end run function
};//end runnable
public void notifyUser()
{
//notify user of resource gain
result = new Intent(this, runGraphics.class);
pendingIntent = PendingIntent.getActivity(
SetupTimerPC1.this,
0,
result,
Intent.FLAG_ACTIVITY_NEW_TASK);
notify = new Notification.Builder(getApplicationContext())
.setContentTitle("2023: Water Gained")
.setContentText("Successfully extracted water.")
.setTicker("2023")
.setWhen(System.currentTimeMillis())
.setContentIntent(pendingIntent)
.setDefaults(Notification.DEFAULT_SOUND)
.setAutoCancel(true)
.setSmallIcon(R.drawable.alienicon)
.build();
notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notify);
}//end notifyUser
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
i = new Intent("polarCap1Status");
i.putExtra("polarCap1Stat", false);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(i);
return Service.START_STICKY;
}//end onStartCommand function
}//end SetupTimerPC1 class
This code uses a Broadcast Receiver
to send a different class a Boolean
value of whether the Button
that starts the Service
can be clicked (meaning when the Service
starts, it tells the other class that the Button
cannot be clicked again until the service is complete.)
here is the code i use for starting the Service
:
//start service for timer
startService(new Intent(runGraphics.this, SetupTimerPC1.class));
Let me know if anymore code is necessary. I really appreciate the help. Thanks.
Upvotes: 0
Views: 68
Reputation: 15775
Your Service
is still running. What you are seeing is the device has slept so the timer won't be accurate. If you check your process list on the device you'll still see your app's process running, even after exiting your Activity
. If you need to ensure your Service
does something at a specific interval (1 min, 1 hour, 1 day, or whatever) then you need to use the AlarmManager
to ensure the device is awakened so your Service
can get time to run. Alternatively, you could use the new JobScheduler
, but it is Android 5.0+ only.
Upvotes: 1