Часть-2 постоянная служба Android на ForeGround, которая запускается с помощью пользовательского интерфейса, работает и в спящем режиме, а также при перезагрузке телефона

Status: Очень благодарен всем, кто помогал и руководствовался здесь и в части-1! Я сделал код из исследований и предоставленной помощи и поместил этот рабочий код в EDIT-1. Критика приветствуется, чтобы сделать код лучше.

Scenario:

Я задал вопрос, упомянутый в части 1, но по какой-то причине я не могу постоянно разрабатывать и корректировать стратегию с помощью кода, который имеет истинную интеграцию и здравый смысл.

Это был длительный вопрос, и вопрос или ответ могли быть завершены или окончательно завершены только в одном эпизоде, поэтому я сделал эту вторую часть в качестве краткого изложения.

Может быть, я некомпетентен или просто обеспокоен чтением разрозненной документации и ответов на разные стратегии, или ответы имеют разные взгляды / стили кодирования.

Постоянная служба Android для ForeGround, которая запускается с помощью пользовательского интерфейса, работает и в спящем режиме, а также при перезагрузке телефона

Question:

Вот то, что я хотел и, наконец, пришел к выводу после наблюдения различных ответов:

Необходимо запускать код каждые 15 минут (даже когда телефон спит). Думаю, понадобятся ли замки от пробуждения?

            //AT boot, check shared preferences to see boolean "serviceEnabled"?
                    //if true, set alarm manager to run a service every 15 minuts.
                    //if false, do nothing.

            //On "enable" button clicked.
                    //make "serviceEnabled" boolean true in shared preferences.
                    //start alarm manager to run a service every 15 minuts.

            //on "Disable" button clicked.
                    //make "serviceEnabled" boolean false in shared preferences.
                    //stop alarm manager and deregister it to run ever.

Может кто-нибудь всесторонне сказать... какой код я должен использовать...? Я смиренно благодарен за головную боль исследования.

Requests:

Пожалуйста, отвечайте, только если вы уверенно и с опытом знаете, что делаете.

EDIT-1-Start:

Вот что я сделал до сих пор. Пожалуйста, не стесняйтесь комментировать или критиковать.

Booter класс, который запускается при загрузке.

public class Booter extends BroadcastReceiver {

      public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();

        if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
          Log.e("boot-status","BOOT_COMPLETED=================================================");
        //  SharedPreferences prefs = context.getSharedPreferences("$MYPACKAGE_preferences",0);
        //  if (prefs.getBoolean("startatboot",false)) {
        if(true){
        Intent updateIntent = new Intent();
        updateIntent.setClass(context, TheService.class);

        PendingIntent pendingIntent = PendingIntent.getService(context, 0, updateIntent, 0);
        AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, java.lang.System.currentTimeMillis()+5000,5000, pendingIntent);

        }
        }
      }


}

Сервисный класс

public class TheService extends Service{

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

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

        pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag");
        wl.acquire();


        startForeground(1, new Notification());

            ////// will do all my stuff here on in the method onStart() or onCreat()?

        Log.e("app-status","ping ====================================================");

        new Thread(new Runnable() {

            @Override
            public void run() {
                wl.release();
                stopSelf(); 
            }
        }).start();


        return START_STICKY;    
    }

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

    public void stop(){
        //if running
        // stop
        // make vars as false
        // do some stopping stuff
        stopForeground(true);


    }





}

Графический интерфейс для запуска / остановки

public class SettingsActivity extends Activity {
  // some code to initialize things

    buttonStop.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            Intent updateIntent = new Intent();
        updateIntent.setClass(SettingsActivity.this, TheService.class);

        PendingIntent pendingIntent = PendingIntent.getService(SettingsActivity.this, 0, updateIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        AlarmManager alarmManager = (AlarmManager)SettingsActivity.this.getSystemService(Context.ALARM_SERVICE);
        alarmManager.cancel(pendingIntent);
        //make sharepred boolean as false

        }
    });

    buttonStart.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            Intent updateIntent = new Intent();
        updateIntent.setClass(SettingsActivity.this, TheService.class);

        PendingIntent pendingIntent = PendingIntent.getService(SettingsActivity.this, 0, updateIntent, 0);
        AlarmManager alarmManager = (AlarmManager)SettingsActivity.this.getSystemService(Context.ALARM_SERVICE);
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, java.lang.System.currentTimeMillis()+5000,5000, pendingIntent);
        //make shared prefs boolean as true

        }
    });

Menifiest

  <?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" /> // irrelevent here
      <uses-permission android:name="android.permission.INTERNET" />        // my app uses these though in service class.
      <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
      <uses-permission android:name="android.permission.WAKE_LOCK" />

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

      <service android:name=".TheService" />
      <receiver android:name=".Booter" >
          <intent-filter>
          <action android:name="android.intent.action.BOOT_COMPLETED" />
          <category android:name="android.intent.category.HOME" />
          </intent-filter>
      </receiver>

      </application>

  </manifest>

EDIT-1-END.

1 ответ

Решение

Если вам нужно только запускать этот код каждые 15 минут. тогда вам действительно не нужно поддерживать сервис в режиме 24/7. На самом деле, не делай этого, это плохая идея. что вам нужно сделать, это:

  1. Используйте AlarmManager для планирования будильника каждые 15 минут. этот сигнал тревоги затем перехватывается с помощью BroadcastReceiver. Этот сигнал тревоги ДОЛЖЕН БЫТЬ RTC_WAKE_UP, чтобы он разбудил телефон, если он находится в режиме глубокого сна, и должен работать в режиме реального времени, поскольку он будет использовать таймер глубокого сна.

  2. Приемник вещания должен будет запустить службу. Теперь этот вызов в сервис должен быть выполнен так:

    • 2.1 получить пробуждение в BroadcastReceiver и приобрести () его.
    • 2.2 запустить IntenetService (этот тип услуг запускается и заканчивается после завершения работы)
    • 2.3 выпустить wakelock в сервисе

Вот хороший пример того, как реализовать это здесь: WakefulIntentService от commonsware. Вам не нужно использовать его как есть, вы можете сделать свой собственный сервис и широковещательный приемник. Просто не забудьте захватить блокировку перед вызовом сервиса и разблокировать его, когда сервис будет выполнен, иначе сервис может не быть вызван.

  1. Ваша служба выполняет все, что вы хотите, каждые 15 минут. Затем вы можете перенести еще один звонок через 15 минут. Вы также можете проверить, включена ли служба с помощью общих настроек, перед выполнением и перепланированием.

Что касается вашей деятельности, контролирующей ваши услуги:

  1. Когда кнопка нажата, проверьте состояние общего предпочтения и сохраните обратное.
  2. Затем отправьте широковещательную рассылку на тот же приемник, который запускает ваш сервис, если они его включили (или запланируйте его на потом).
  3. Если он был отключен, то отмените все расписания для службы.

Что касается вашего требования загрузки:

  1. Объявите в своем манифесте, что тот же получатель, который запускает вашу службу, вызывается при вызове действия android.intent.action.BOOT_COMPLETED.
  2. Объявите разрешение: android.permission.RECEIVE_BOOT_COMPLETED

Пример манифеста:

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

Пример отмены и планирования сигналов тревоги:

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);
}

Пример запуска службы при загрузке:

@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);
}

А на сервисе снимаем блокировку

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");
    }
  }
}

Вот и все.

Другие вопросы по тегам