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

六眼飞鱼酱① 提交于 2019-11-29 02:01:27
Sharad Mhaske

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 :)

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.

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>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!