Search code examples
javaandroidservicebroadcastreceiverimagebutton

BroadcastReceiver from Service not functioning correctly when app is closed


I am creating an app that has an imagebutton that starts a Service when it is clicked. The Service contains a handler that I use as a 24 hour timer. When the Service is started, the button is disabled so it cannot be clicked again. Then when the time is up the button is enabled again. This all works great until the app is fully closed. If the app is fully closed the Service continues to run as it should except there is a problem with the BroadcastReceiver. If the app is closed and then reopened, the button to start the service can be clicked even when the service is already running. I am not sure why the button is enabled when the app reopens even though the service is still running.

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, 2000); //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 < 5)//144
        {
            handler.postDelayed(runnable, 2000); //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

Here is the code for the button that receives the boolean from the BroadcastReceiver:

    //setup image buttons
    polarCap1 = (ImageButton) findViewById(R.id.polarCapButton1);
    polarCap1.setOnClickListener(new OnClickListener()
    {
        @Override
        public void onClick(View v)
        {   
            Toast.makeText(getApplicationContext(), "Attempting to Gain Resources", Toast.LENGTH_SHORT).show();

            if (polarCap1.isEnabled() && appSound)
            {
                water = new SoundPool(2, AudioManager.STREAM_MUSIC, 0);
                playSound = water.load(runGraphics.this, R.raw.watersound, 1);

                //play water sound
                water.setOnLoadCompleteListener(new OnLoadCompleteListener()
                {

                    @Override
                    public void onLoadComplete(SoundPool soundPool,
                            int sampleId, int status) 
                    {
                        water.play(playSound, 1, 1, 0, 0, 1);
                    }//end onLoadComplete

                });//end setOnLoadCompleteListener
            }//end if

            //button cannot be clicked
            polarCap1.setEnabled(false);

            //start service for timer
            startService(new Intent(runGraphics.this, SetupTimerPC1.class));

            //stop service for timer
            //stopService(new Intent(runGraphics.this, SetupTimerPC1.class));

            //broadcast receiver to allow button to be clicked again
            mMessageReceiver1 = new BroadcastReceiver()
            {
                @Override
                public void onReceive(Context context, Intent intent) 
                {
                    clickOnOff1 = intent.getBooleanExtra("polarCap1Stat", false);
                    polarCap1.setEnabled(clickOnOff1);
                    updateScores();
                }//end onReceive function
            };
            LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(mMessageReceiver1, new IntentFilter("polarCap1Status"));
        }//end onClick function         
    });//end setOnClickListener

Thank you so much for any help.


Solution

  • If you want to keep what you are doing, you can add this code to check the status of your service in onCreate() with isMyServiceRunning(SetupTimerPC1.class). If it is running then you can disable the button:

    private boolean isMyServiceRunning(Class<?> serviceClass) {
    ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (serviceClass.getName().equals(service.service.getClassName())) {
            return true;
        }
    }
    return false;
    }