sboehnke
sboehnke

Reputation: 287

Service is stopping on app close when it didn't before

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

Answers (1)

Larry Schiefer
Larry Schiefer

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

Related Questions