part-1 persistent foreGround android service that starts by UI, works at sleep mode too, also starts at phone restart
Asked Answered
S

3

11

Status:--- I equally accept Karakuri's and Sharad Mhaske's answer, but since Sharad Mhaske answer after the start of bounty, the bounty should go to him.

Part-2 made: part-2 persistent foreGround android service that starts by UI, works at sleep mode too, also starts at phone restart

In stack overflow, only one answer may be accepted. I see both answers as acceptable but one has to be chosen (I chosed at random).

Viewers are invited to up/down vote answers/question to appreciate the effort!. I upvoted Karakuri's answer to compensate reputation.

Scenario:---

  1. I want to make the user click a start/stop button and start/stop a service from UI activity. I have made the UI so dont care about that. But Just the logic of the Button click event.

  2. Do not want the service to be bound to the UI activity. If activity closes, the service should keep running.

  3. Want to make most effort that the service be persistent and does not stops in any case. Will give it most weight and run it as ForGroundSerice as it has a higher hierarchy of importance. (hope that's ok?)

  4. Unless the stop button is clicked by my apps UI, do not want it to be stopped (or should restart itself) Even if android reclaim memory. I and the user of the phone, both are/will be aware of it. The service is most of importance. Even at sleep.

    details= my app do some operations, sleep for user provided time (15 minuts usually), wakes and perform operations again. this never ends)

    If I need AlarmManager, How to implement that? or any other way? Or just put the operations in a neverending while loop and sleep for 15 minuts at the end?

  5. When the service is started (by clicked on start button). It should make an entry so that it auto starts if phone restarts.

QUESTION:---

Primary Question:

  1. Just can't get an optimal strategy for the scenario... and also stuck on small bits of code, which one to use and how.

  2. Gathered bits and pieces from stackoverflow.com questions, developer.android.com and some google results but cannot implement in integration.

  3. Please read out the Requests Section.

Secondary Question:

The comments in my code are those small questions.

Research and Code:---

Strategy:

            want this to happen every time the user opens the UI.

    //Start Button:-----
    //check if ForGroundService is running or not. if not running, make var/settings/etc "serviceStatus" as false 
            <-------(how and where to stare this and below stated  boolean?)
    //start ForGroundService 
            <-------(how?)
    //make "SericeStatus" as true

    //check if "ServiceStartOnBoot" is false
    //Put ForGroundService to start on boot -------(to make it start when ever the phone reboots/restarts) 
            <-------(how?)
    //make "ServiceStartOnBoot" as true
            // the boolean can also be used to check the service status.



    //Stop Button:------
    //makes SericeStatus and ServiceStartOnBoot as false
    //stops service and deletes the on boot entry/strategy

Activity UI class that starts/stops the service:

public class SettingsActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_settings);

        //some button here to start / stop and their onClick Listners



    Intent mySericeIntent = new Intent(this, TheService.class);
    }


    private void startMyForGroundService(){

    startService(mySericeIntent);

    }

    private void stopMyForGroundSerice(){
        stopService(mySericeIntent);
                          /////// is this a better approach?. stopService(new Intent(this, TheService.class));          
                          /////// or making Intent mySericeIntent = new Intent(this, TheService.class);
                          /////// and making start and stop methods use the same?

                          /////// how to call stopSelf() here? or any where else? whats the best way?
    }

}

The Service class:

  public class TheService extends Service{

      @Override
      public IBinder onBind(Intent arg0) {
          // TODO Auto-generated method stub
          return null;
      }

      @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
          startForeground(1, new Notification());
                                  ////// will do all my stuff here on in the method onStart() or onCreat()?

          return START_STICKY;    ///// which return is better to keep the service running untill explicitly killed. contrary to system kill.
                                  ///// http://developer.android.com/reference/android/app/Service.html#START_FLAG_REDELIVERY

          //notes:-//  if you implement onStartCommand() to schedule work to be done asynchronously or in another thread, 
          //then you may want to use START_FLAG_REDELIVERY to have the system re-deliver an Intent for you so that it does not get lost if your service is killed while processing it
      }

      @Override
        public void onDestroy() {
          stop();
        }

      public void stop(){
          //if running
          // stop
          // make vars as false
          // do some stopping stuff
          stopForeground(true);
                                  /////// how to call stopSelf() here? or any where else? whats the best way?

      }


  }

The Menifest file:

      <?xml version="1.0" encoding="utf-8"?>
      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.example.myapp"
      android:versionCode="1"
      android:versionName="1.0" >

      <uses-sdk
          android:minSdkVersion="10"
          android:targetSdkVersion="17" />

      <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
      <uses-permission android:name="android.permission.INTERNET" />

      <application

          android:allowBackup="true"
          android:debuggable="true"
          android:icon="@drawable/ic_launcher"
          android:label="@string/app_name"
          android:theme="@style/AppTheme" >
          <activity
          android:name="com.example.myapp.MainActivity"
          android:label="@string/app_name" >
          <intent-filter>
              <action android:name="android.intent.action.MAIN" />

              <category android:name="android.intent.category.LAUNCHER" />
          </intent-filter>
          </activity>
          <activity
          android:name="com.example.myapp.SettingsActivity"
          android:label="@string/title_activity_settings" >
          </activity>

      </application>

      </manifest>

References:---

Android - implementing startForeground for a service? pointing answer 1, example code.

Trying to start a service on boot on Android

Android: Start Service on boot?

http://developer.android.com/guide/components/services.html

http://developer.android.com/reference/android/app/Service.html

http://developer.android.com/training/run-background-service/create-service.html not preffered by me.

http://developer.android.com/guide/components/processes-and-threads.html my starting point of research

Requests:---

I think this question is a normal practice for most people who are dealing with services. In that vision, please only answer if you have experience in the scenario and can comprehensively explain the aspects and strategy with maximum sample code as a complete version so it would be a help to the community as well.

Vote up and down (with responsibility) to the answers as it matters to me who shared their views, time and experience and helped me and the community.

Skyros answered 9/6, 2013 at 2:28 Comment(8)
Recognizing that this is not a best practice and that the idea of an always-on service is actually a bad idea and that you can most likely achieve your scenario with other mechanisms seems to be something of a rite of passage that new-to-android developers go through, which is why you see a lot of questions about it. Check out androidguys.com/2009/09/09/…Walczak
@Jc 1. very nice link. thanks. I agree, and I am aware that its not a good idea. But if the service is very very crucial and important? 2. My question is far more than just making it unkillable or not.Skyros
Very crucial and important? Sounds like a job for dedicated hardware. If your service keeps the CPU on permanently (which it would need to do in order to operate when the screen is off - check out PARTIAL_WAKE_LOCK) you're going to impact battery life - keep in mind a service isn't very effective if the battery is dead. :)Walczak
Note that #4 is not really feasible, you can't prevent your service from being stopped by the user from the settings page and you can't stop the OS from killing it to reclaim memory, but you can certainly use AlarmManager to mitigate some of this. As an example, you could design your service to run for a period of time and then stop itself, and then use AlarmManager to run it every so often (in theory you could keep it running almost all the time this way).Walczak
@Jc very correct again. but I and the user of the phone, both are/will be aware of it. The service is most of importance. even at sleep. Now lets ignore 4. momentarily and talk about the strategy?Skyros
Recommended strategy: Establish AlarmManager usage at bootup to provide intermittent "awakenings" of your service so it can request a wake lock, check for any work to do, do the work, then release the wake lock.Walczak
nice. have to lock further things which the app uses, like wifi etc, when the app wakes up. just need a design / code implementation for my logic . and be aware of alternatives that I can do too. Thanks.Skyros
hi @Masood Ahmad i am facing some different issue then yours, 1st- My service get restarted if i relaunch my app by pressing App icon from launcher, 2nd- My service gets terminated or destroyed or restarted if user clears/swipe it from recent appList. Do you have any solution to overcome these 2 issues?Alfreda
N
3

Que:Want to make most effort that the service be persistent and does not stops in any case. Will give it most weight and run it as ForGroundSerice as it has a higher hierarchy of importance. (hope that's ok?)

Answer:you need to start service with using START_STICKY Intent flag.

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}

Que:If I need AlarmManager, How to implement that? or any other way? Or just put the operations in a neverending while loop and sleep for 15 minuts at the end?

Answer:you need to register alarmmanager within service for the time after to some task. //register alarm manager within service.

PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, new         Intent("com.xxxxx.tq.TQServiceManager"), PendingIntent.FLAG_UPDATE_CURRENT);

        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

    alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 1000 , 30 * 1000 , pendingIntent);

//now have a broadcastreceiver to receive this intent.

class Alarmreceiver extends Broadcastreceiver
{
   //u can to task in onreceive method of receiver.
}

//register this class in manifest for alarm receiver action.

Que:When the service is started (by clicked on start button). It should make an entry so that it auto starts if phone restarts.

Answer:use broadcast reciver to listen for onboot completed intent.

public class StartAtBootServiceReceiver extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        try {           
            if( "android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {                

                ComponentName comp = new ComponentName(context.getPackageName(), LicensingService.class.getName());
                ComponentName service = context.startService(new Intent().setComponent(comp));
                if (null == service){
                    // something really wrong here
                    //Log.Write("Could not start service " + comp.toString(),Log._LogLevel.NORAML);
                }
            }
            else {
                //Log.Write("Received unexpected intent " + intent.toString(),Log._LogLevel.NORAML);   
            }
        } catch (Exception e) {
            //Log.Write("Unexpected error occured in Licensing Server:" + e.toString(),Log._LogLevel.NORAML);
        }
    }
}

//need to register this receiver for Action_BOOTCOMPLETED intent in manifest.xml file Hope this helps you clear out things :)

Nobelium answered 15/6, 2013 at 11:49 Comment(2)
Thanks for the nice answer! Despite I asked too much that could be answered all at one place. Have updated the question status.Skyros
part-2 made #17252243Skyros
S
2

If you start a service with startService(), it will keep running even when the Activity closes. It will only be stopped when you call stopService(), or if it ever calls stopSelf() (or if the system kills your process to reclaim memory).

To start the service on boot, make a BroadcastReceiver that just starts the service:

public class MyReceiver extends BroadcastReceiver {
    public void onReceive(Context context, Intent intent) {
        Intent service = new Intent(context, MyService.class);
        context.startService(service);
    }
}

Then add these to your manifest:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application ... >

    <receiver android:name="MyReceiver" 
        android:enabled="false" >
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>
</application>

Notice that the receiver is not enabled at first. When the user starts your service, use PackageManager to enable the receiver. When the user stops your service, use PackageManager to disable the receiver. In your Activity:

PackageManager pm = getPackageManager();
ComponentName receiver = new ComponentName(this, MyReceiver.class);
pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,  PackageManager.DONT_KILL_APP);

Use same method with PackageManager.COMPONENT_ENABLED_STATE_DISABLED to disable it.

Shellacking answered 9/6, 2013 at 3:7 Comment(6)
thanks for the reply! --- 1. Intent service = new Intent(context, MyService.class); should be Intent intent = new Intent(context, MyService.class); ? --- 2. how to run it as forGround? --- 3. will package manager help even if the phone reboots and user wants to check (by UI with some boolean/text) whether service is running or not? --- 4. is the menifest script you gave enough to start the service on boot? --- 5. My question is of far more detail requesting. hope you can give/tryto give other answers --- 6. Is this the only / best approach or do I have more options?Skyros
7. I want the app to be running even when the phone sleeps. details= my app do some operations, sleep for user provided time (15 minuts usually), wakes and perform operations again. this never ends) --- 8. I have edited point no. 4 of Scenario.Skyros
1. I edited my code. 2. Use startForeground() and stopForeground(). You can start when your service receives the onStartCommand() callback. 3. I think the PackageManager code will work even across reboots. If it does not, then you should instead store the current state in SharedPreferences and check that value in your Receiver that runs on boot completed. In that case remove android:enabled="false" from the manifest entry. 4. The manifest code should work.Shellacking
5. I've given you about as much as I can, it should give you a good starting point. I don't have the time or inclination to build this myself and test it, you'll just have to try things out. 6. Don't know. 7. If you only need to run an operation every 15 mins, use AlarmManager to fire a PendingIntent that starts your Service. If it doesn't need to run all the time, extend IntentService instead since it stops itself after finishing execution of onHandleIntent(). This might also get around the system possibly killing your service.Shellacking
Thanks Karakuri, for the lovely guide!Skyros
part-2 made #17252243Skyros
B
0

I have made something like this myself but I learned a lot while developing it and discovered it is not completely necesary to have the service running all day draining your battery. what I made is the following:

Implement a Service that reacts to events. In my particular I wanted to automate my Wifi and mobile data connection. so i react to events like wifi connecting and disconnecting, screen turning on and off, etc. So this service executes what ever needs to be executed responding to this event and then stops, scheduling any further actions with the AlarmManager if so needed.

now, this events can by timers like you said yourself every 15 minutes it does something and sleeps, that sounds to me that you really dont want the service running 24/7 but just executing something every 15 minutes. that is perfectly achievable with the AlarmManager without keeping your service running forever.

I recommend implementing this service deriving from commonsware's WakefulIntentService.

This class already handles the wakeLock for you so that you can exceute code even if phone is asleep. it will simply wakeup execute and go back to sleep.

Now. About your question regarding the activity starting and stoping the service. you can implement in the button that it starts or cancels the AlarmManager alarm. Also you can use the sharedPreferences to store a simple boolean that tells you if it is enabled or not so the next time your service runs it can read the value and know if it should continue or stop.

If you implement it as a event-reactive service as i said, your button can even react to broadcast intents so that your activity doesn't even have to call the service directly just broadcast an intent and the service can pick it like other events. use a BroadcastReceiver for this.

I'll try to give examples but be wary that what you're asking is a lot of code to put it in one place...

BootReceiver:

public class BootReceiver extends BroadcastReceiver
{
  private static final String TAG = BootReceiver.class.getSimpleName();

  @Override
  public void onReceive(final Context context, final Intent intent)
  {
    final Intent in = new Intent(context, ActionHandlerService.class);
    in.setAction(Actions.BOOT_RECEIVER_ACTION);  //start the service with a flag telling the event that triggered
    Log.i(TAG, "Boot completed. Starting service.");
    WakedIntentService.sendWakefulWork(context, in);
  }
}

Service:

public class ActionHandlerService extends WakedIntentService
{
  private enum Action
  {
    WIFI_PULSE_ON, WIFI_PULSE_OFF, DATA_PULSE_ON, DATA_PULSE_OFF, SCREEN_ON, SCREEN_OFF, WIFI_CONNECTS, WIFI_DISCONNECTS, WIFI_CONNECT_TIMEOUT, WIFI_RECONNECT_TIMEOUT, START_UP, BOOT_UP
  }

  public ActionHandlerService()
  {
    super(ActionHandlerService.class.getName());
  }

  @Override
  public void run(final Intent intent)
  {
    mSettings = PreferenceManager.getDefaultSharedPreferences(this);
    mSettingsContainer.enabled = mSettings.getBoolean(getString(R.string.EnabledParameter), false);
    if (intent != null)
    {
      final String action = intent.getAction();
      if (action != null)
      {
        Log.i(TAG, "received action: " + action);
        if (action.compareTo(Constants.Actions.SOME_EVENT) == 0)
        {
          //Do what ever you want
        }
        else
        {
          Log.w(TAG, "Unexpected action received: " + action);
        }
      }
      else
      {
        Log.w(TAG, "Received null action!");
      }
    }
    else
    {
      Log.w(TAG, "Received null intent!");
    }
  }
}

And your Manifest could go something like this:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.yourcompany.yourapp"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="7"
        android:targetSdkVersion="17" />

    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <application
        android:allowBackup="false"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <activity
            android:name="com.yourcompany.yourapp.activities.HomeActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service android:name="com.yourcompany.yourapp.services.ActionHandlerService" />
        <receiver android:name="com.yourcompany.yourapp.receivers.BootReceiver" >
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <category android:name="android.intent.category.HOME" />
            </intent-filter>
        </receiver>

    </application>
</manifest>
Bustard answered 11/6, 2013 at 19:11 Comment(2)
Even though I have not been marked as a correct answer, you will find troubles with what you accepted as answer. In the marked answer, the service will restart in case it is shut down. But the problem is, that your service might not necessarily need to be kept running but rather be called everytime it's needed and shut down again. Also, the fact that the service is running doesn't mean it will not pause when the cellphone enters deep sleep. That's why I precented you with the WakefulIntentService that will execute the task with a wakelock and sleep again (you can reschedule the next task).Bustard
ok. I would keep that in mind. thanks again!. 1. I dont like to go with a third party code that is in github. 2. part-2 made #17252243Skyros

© 2022 - 2024 — McMap. All rights reserved.