2

I have a service that performs background updates.

I want to give the user the the option to disable the updates when their battery percentage reaches a certain level.

From my research, I'm going to use a receiver in the onCreate method of my Service class, eg:

 public class MainService extends Service  
 {  
     @Override
     public void onCreate()
     {      
        this.registerReceiver(this.BatInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
     }

    private BroadcastReceiver BatInfoReceiver = new BroadcastReceiver(){  
         @Override  
         public void onReceive(Context arg0, Intent intent) {  
           int level = intent.getIntExtra("level", 0);  
    }  
  };
 }

I'm assuming that the best practice is to leave the service running, check the battery level in the service, and not perform the CPU-intensive code, based on the percentage?

I don't actually need to stop the service itself and start it up again, based on the battery percentage?

UPDATE:

This seems to be a better solution, but not 100% sure. I registered a BroadcastReceiver in the AndroidManifest:

<receiver android:name="BatteryReceiver" /> 

Then created a BroadcastReceiver:

 public class BatteryReceiver extends BroadcastReceiver 
 {  
     @Override
     public void onReceive(final Context context, final Intent intent) 
     {      
         final int currentBatteryPercent = intent.getIntExtra("level", 0);
        final int disableBatteryPercent = Integer.parseInt(PreferenceManager.getDefaultSharedPreferences(context).getString("batteryPercent", 0);

        //AlarmReceiver is the service that performs the background updates
         final ComponentName component = new ComponentName(context, AlarmReceiver.class);

         if (currentBatteryPercent < disableBatteryPercent)
         {
             context.getPackageManager().setComponentEnabledSetting(component, PackageManager.COMPONENT_ENABLED_STATE_DISABLED , PackageManager.DONT_KILL_APP);
         }
         else
         {
             context.getPackageManager().setComponentEnabledSetting(component, PackageManager.COMPONENT_ENABLED_STATE_ENABLED , PackageManager.DONT_KILL_APP);
         }
      }
 }
jimmym715
  • 1,512
  • 1
  • 16
  • 25
Kris B
  • 3,436
  • 9
  • 64
  • 106

2 Answers2

2

That's right. What you will typically do is schedule some broadcast intent for an update (perhaps through an AlarmManager). When you get the notification that there is a low battery, you will stow this away in your service, and then before doing an update, check to ensure that the battery isn't too low. here is a good tutorial of watching the battery level. You shouldn't do much when handling this intent, just stick the battery level somewhere and (before doing an update) make sure it's appropriately "full."

Your update is a really bad way to stop an app. In general, asking the package manager to stop your component is much more of a hack than a solution. Instead, you should move some code into the component that actually does the updating, and store / update the information for the battery info there. Before you do an update, you check the battery level and don't proceed unless it's at a level where you feel comfortable updating the app. Using a broadcast receiver is fine, but you need to store the level somewhere (perhaps a sharedprefs). Instead, this is why putting the receiver within the service where you do the updating is probably best.

Kristopher Micinski
  • 7,572
  • 3
  • 29
  • 34
  • Thanks, just needed some validation. – Kris B Mar 18 '12 at 17:49
  • The only reason I brought up the package manager, is based on this question, which was replied to by one of the Android Framework engineers: http://stackoverflow.com/questions/2782448/android-how-to-start-a-service-at-boot-based-on-user-settings/3465986 Maybe it's not the same though, as that question is about disabling a service at boot, instead of at a certain battery level? – Kris B Mar 18 '12 at 18:48
  • Yes, you shouldn't really be using the context to stop components within your app, that strikes me as really bad practice and hacky. (Killing things off, even if it doesn't kill the app, is always scary and leads to some sticky behavior). A much cleaner solution is to store the level somewhere in the AlarmManager which actually does the updating, this is (in my opinion) by far the cleanest way to go about it. – Kristopher Micinski Mar 18 '12 at 18:53
  • Cool, I appreciate your responses. – Kris B Mar 18 '12 at 18:59
  • No problem. I'd also point out that sticking this code in your service is something you should do anyway, because you'll probably want to let the user configure some settings about when they want the app to update itself (for example, when connected to wifi only? etc..) and this is by far the best place to put it, because that's where it's actually used! – Kristopher Micinski Mar 18 '12 at 19:01
1

Is it possible to manage this requirement with a broadcastReceiver instead of running a service continuously ?

public void onReceive(final Context context, final Intent intent) {

            if(intent != null && intent.getAction() != null) {
                    String action = intent.getAction();

                    if(action.equals(Intent.ACTION_BOOT_COMPLETED)) {
                            // Set alarm
                    }
                    else if(action.equals(Intent.ACTION_BATTERY_LOW)) {
                            setLocationAlarmReceiverEnabled(context, false);
                    }
                    else if(action.equals(Intent.ACTION_BATTERY_OKAY)) {
                            setLocationAlarmReceiverEnabled(context, true);
                    }
            }
    }
Pavandroid
  • 1,586
  • 2
  • 15
  • 30
  • You shouldn't worry about the service running "continuously," unless you're holding a wake lock, the scheduling and impact on the CPU between these shouldn't really make a difference. – Kristopher Micinski Mar 18 '12 at 17:59
  • Actually, this seems a little cleaner, than running the service. – Kris B Mar 18 '12 at 18:13
  • But you don't need to stick it in a service, or anything, you could just as easily stick that in an activity. The only thing you need is the BroadcastReciever, and you could stick that wherever you want, as long as your register it with the main context.. I'm not sure you really understand how the system is scheduling things... It's the broadcastreceiver that gets it, it doesn't matter where it's running, and if you're doing updating within a service (which you should be), then putting the receiver there will work better, as you'll be able to keep state there as well. – Kristopher Micinski Mar 18 '12 at 18:15
  • Thanks for the response. Check out my OP, I added an update. Let me know if that is a better solution or not. – Kris B Mar 18 '12 at 18:24