Как всегда запустить сервис в фоновом режиме? - PullRequest
73 голосов
/ 02 апреля 2010

Я нахожусь в процессе создания приложения, похожего на встроенное приложение SMS.

Что мне нужно:

  • служба, которая всегда работает в фоновом режиме
  • каждые 5 мин. служба проверяет текущее местоположение устройства и вызывает веб-сервис
  • при соблюдении определенных критериев служба должна генерировать уведомление (как приложение SMS)
  • при нажатии на уведомление пользователь попадает в приложение (как приложение SMS)
  • когда приложение установлено, служба должна быть запущена
  • при перезагрузке устройства служба должна быть запущена

Что я пробовал:
- запуск обычного сервиса, который работал нормально, пока Android не убил сервис
- с помощью AlarmManager сделать 5 мин. интервальный звонок в сервис. Но я не смог заставить эту работу.

Ответы [ 4 ]

33 голосов
/ 02 апреля 2010

служба, которая всегда работает в фон

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

каждые 5 мин. служба проверяет текущее местоположение устройства и вызывает веб-сервис

Использовать AlarmManager.

с помощью AlarmManager сделать 5 минимум интервальный звонок в сервис. Но я не смог сделать эту работу.

Вот пример проекта , показывающий, как его использовать, а также WakefulIntentService, чтобы вы не спали, пытаясь выполнить весь веб-сервис.

Если у вас продолжаются проблемы с этим, откройте новый вопрос о конкретных вещах, с которыми вы сталкиваетесь AlarmManager, которые вызывают у вас горе.

26 голосов
/ 02 апреля 2010

Одно из моих приложений делает что-то очень похожее. Чтобы активировать услугу через определенный период времени, я рекомендую postDelayed()

Есть поле обработчика:

private final Handler handler = new Handler();

и переподготовка Runnable

private final Runnable refresher = new Runnable() {
  public void run() {
    // some action
  }
};

Вы можете запускать свои уведомления в рабочем режиме.

О сервисном построении и после каждого запуска запуска это так:

handler.postDelayed(refresher, /* some delay in ms*/);

В onDestroy() удалить пост

handler.removeCallbacks(refresher);

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

<receiver android:name="com.example.ServiceAutoStarter">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
  </receiver>

и ServiceAutoStarter выглядит так:

public class ServiceAutoStarter extends BroadcastReceiver {
  @Override
  public void onReceive(Context context, Intent intent) {
    context.startService(new Intent(context, UpdateService.class));
  }
}

Остановить ОС, чтобы убить службу, довольно сложно. Также ваше приложение может иметь RuntimeException и сбой, или ваша логика может зависнуть.

В моем случае, казалось, помогло всегда обновлять сервис на экране с BroadcastReceiver. Поэтому, если цепочка обновлений остановится, она будет воскрешена, когда пользователь использует свой телефон.

В сервисе:

private BroadcastReceiver screenOnReceiver; 

К вашим услугам onCreate()

screenOnReceiver = new BroadcastReceiver() {

  @Override
  public void onReceive(Context context, Intent intent) {
    // Some action
  }
};

registerReceiver(screenOnReceiver, new IntentFilter(Intent.ACTION_SCREEN_ON));

Затем отмените регистрацию услуги на onDestroy() с помощью

unregisterReceiver(screenOnReceiver);
3 голосов
/ 31 декабря 2015

Вы можете сделать это с помощью простой реализации:

public class LocationTrace extends Service implements LocationListener{

    // The minimum distance to change Updates in meters
    private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters
    private static final int TWO_MINUTES = 100 * 10;

    // The minimum time between updates in milliseconds
    private static final long MIN_TIME_BW_UPDATES = 1000 * 10; // 30 seconds

    private Context context;

    double latitude;
    double longitude;

    Location location = null;
    boolean isGPSEnabled = false;
    boolean isNetworkEnabled = false;
    protected LocationManager locationManager;


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

        this.context = this;
        get_current_location();
//      Toast.makeText(context, "Lat"+latitude+"long"+longitude,Toast.LENGTH_SHORT).show();
        return START_STICKY;
    }


    @Override
    public void onLocationChanged(Location location) {
        if((location != null) && (location.getLatitude() != 0) && (location.getLongitude() != 0)){

            latitude = location.getLatitude();
            longitude = location.getLongitude();

            if (!Utils.getuserid(context).equalsIgnoreCase("")) {
                Double[] arr = { location.getLatitude(), location.getLongitude() };

               // DO ASYNCTASK
            }
        }

    }


    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {

    }

    @Override
    public void onProviderEnabled(String provider) {

    }

    @Override
    public void onProviderDisabled(String provider) {

    }

    /*
    *  Get Current Location
    */
    public Location get_current_location(){

        locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);

        isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);

        isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

        if(!isGPSEnabled && !isNetworkEnabled){



        }else{
            if (isGPSEnabled) {

                if (location == null) {
                    locationManager.requestLocationUpdates(
                            LocationManager.GPS_PROVIDER,
                            MIN_TIME_BW_UPDATES,
                            MIN_DISTANCE_CHANGE_FOR_UPDATES, this);

                    if (locationManager != null) {
                        location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
                        if (location != null) {
                            latitude = location.getLatitude();
                            longitude = location.getLongitude();
        //                  Toast.makeText(context, "Latgps"+latitude+"long"+longitude,Toast.LENGTH_SHORT).show();
                        }
                    }
                }
            }
            if (isNetworkEnabled) {

                locationManager.requestLocationUpdates(
                        LocationManager.NETWORK_PROVIDER,
                        MIN_TIME_BW_UPDATES,
                        MIN_DISTANCE_CHANGE_FOR_UPDATES, this);

                if (locationManager != null) {

                    if (location != null) {
                        latitude = location.getLatitude();
                        longitude = location.getLongitude();
        //              Toast.makeText(context, "Latgps1"+latitude+"long"+longitude,Toast.LENGTH_SHORT).show();
                    }
                }
            }
        }

        return location;
    }


    public double getLatitude() {
        if(location != null){
            latitude = location.getLatitude();
        }
        return latitude;
    }

    public double getLongitude() {
         if(location != null){
             longitude = location.getLongitude();
         }

        return longitude;
    }


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        if(locationManager != null){
            locationManager.removeUpdates(this);
        }
        super.onDestroy();
    }

}

Вы можете начать обслуживание следующим образом:

/*--Start Service--*/
startService(new Intent(Splash.this, LocationTrace.class));

В декларации:

 <service android:name=".LocationTrace">
            <intent-filter android:priority="1000">
                <action android:name="android.location.PROVIDERS_CHANGED"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
  </service>
0 голосов
/ 17 апреля 2018

этими тремя шагами вы можете каждые 5 минут пробуждать большинство устройств Android:

1.установите альтернативный AlarmManager для различных API:

AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(getApplicationContext(), OwnReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(getApplicationContext(), 0, i, 0);

if (Build.VERSION.SDK_INT >= 23) {
am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
}
else if (Build.VERSION.SDK_INT >= 19) {
am.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
} else {
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
}

2.создайте свой собственный статический BroadcastReceiver:

public static class OwnReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

       //do all of your jobs here

        AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        Intent i = new Intent(context, OwnReceiver.class);
        PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);

        if (Build.VERSION.SDK_INT >= 23) {
            am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
        }
        else if (Build.VERSION.SDK_INT >= 19) {
            am.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
        } else {
            am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
        }
    }
}

3.добавьте <receiver> к AndroidManifest.xml:

<receiver android:name=".OwnReceiver"  />
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...