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

荒凉一梦 提交于 2019-11-30 10:10:17

If you only need to run this code every 15 minutes. then you really don't need to keep the service running 24/7. Really, don't do it, it is bad idea. what you need to do is this:

  1. Use AlarmManager to schedule an alarm every 15 minutes. this alarm is then catched with a BroadcastReceiver. This alarm HAS TO BE RTC_WAKE_UP so that it wakes the phone up if it is in deep sleep and it has to be real time since it will use the deep sleep timer.

  2. Broadcast receiver will have to start a service. now this call to the service has to be done like this:

    • 2.1 get a wakelock in the BroadcastReceiver and acquire() it.
    • 2.2 start a IntenetService (This type of services start and end themselves after work is done)
    • 2.3 release the wakelock in the service

There is a good example of how to implement this here: commonsware's WakefulIntentService. You don't have to use it as is, you can make your own service and broadcast receiver. Just remember to acquire the lock before calling the service and releasing it when the service is done, otherwise the service might not get called.

  1. Your service does whatever you want to execute each 15 minutes. Then you can reschedule another call in another 15 minutes. You can also check if the service is enabled via the shared preferences before executing and rescheduling.

As for your activity controlling your service:

  1. When the button is pressed check the shared preference state and save the opposite.
  2. Then send a broadcast to your same receiver that starts your service if they have enabled it (or schedule it for later).
  3. If it was disabled, then cancel any schedules for the service.

As for your boot up requirement:

  1. Declare in your manifest that the same receiver that starts your service is called when the action android.intent.action.BOOT_COMPLETED is called.
  2. Declare the permission: android.permission.RECEIVE_BOOT_COMPLETED

An example manifest:

<?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>

Example of cancelling and scheduling alarms:

public synchronized static void disableTimers(final Context context)
{
  Log.i(TAG, "Canceling Alarms");
  final Intent in = new Intent(Constants.Actions.TIMER_ACTION);
  final PendingIntent pi = PendingIntent.getBroadcast(context, 0, in, PendingIntent.FLAG_UPDATE_CURRENT);
  ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).cancel(pi);
}

public synchronized static void enableTimer(final Context context)
{
  Log.i(TAG, "Enabling Alarm");
  final Intent in = new Intent(Constants.Actions.TIMER_ACTION);
  final PendingIntent pi = PendingIntent.getBroadcast(context, 0, in, PendingIntent.FLAG_UPDATE_CURRENT);
  ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + FIFTEEN_MINUTES, pi);
}

Example of starting the service on boot up:

@Override
public void onReceive(final Context context, final Intent intent)
{
  final Intent in = new Intent(context, MyService.class);
  in.setAction(Actions.BOOT_RECEIVER_ACTION);
  Log.i(TAG, "Boot completed. Starting service.");
  MyService.acquireLock();
  context.startService(in);
}

And on the service release the lock

private static volatile WakeLock mStaticWakeLock = null;

private synchronized static WakeLock getLock(final Context context)
{
  if (mStaticWakeLock == null)
  {
    final PowerManager mgr = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    mStaticWakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_PARAMETER);
    mStaticWakeLock.setReferenceCounted(true);
  }
  return mStaticWakeLock;
}

@Override
protected final void onHandleIntent(final Intent intent)
{
  try
  {
    run(intent);
  }
  finally
  {
    final WakeLock lock = getLock(getApplicationContext());
    if (lock.isHeld())
    {
      lock.release();
      Log.i(TAG, "Releasing WakeLock");
    }
  }
}

That's it.

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