2010-04-02 4 views
68

Я создаю приложение, похожее на встроенное приложение SMS.Как всегда запускать службу в фоновом режиме?

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

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

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

ответ

26

Одно из моих приложений делает что-то очень похожее. Для того, чтобы разбудить службы после определенного периода я рекомендую 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)); 
    } 
} 

Остановка OS от убийства сервиса сложно. Также ваше приложение может иметь 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); 
+1

Я обычно как ваши ответы, но этот ... не так много. :-(Например, вы предлагаете, чтобы служба регистрировала приемник, чтобы воскресить себя после его убийства. Получатель будет убит вместе с сервисом, поэтому это не должно иметь никакого эффекта. Более того, вся концепция вечного служения ужасна на Android и является причиной, по которой пользователи борются с убийцами задач или экраном Running Services в приложении «Настройки». Очень мало случаев, когда требуется действительно вечный сервис - в большинстве случаев достаточно «AlarmManager». – CommonsWare

+4

Спасибо, CWare, я, вероятно, должен был сделать более ясным, что Resurrector должен защитить от сбоя логики и многих вещей, которые могут остановить цепочку событий, которые разбудили службу, поскольку то, что приписывается системе, закрывающей службу, часто может быть чем-то другим . Я рассмотрю подход диспетчера будильника, я смутно помню, как это пытались сделать некоторое время назад и не смог заставить его работать. –

31

сервис, который всегда работает в фон

Это в любом смысле этого термина not possible, как вы открыли. Это также bad design.

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

AlarmManager Используйте.

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

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

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

+0

Я использовал этот образец проекта, и я поставил журнал и подождал 10 минут, ничего не работает? Мне нужно позвонить в службу, чтобы начать? –

+2

@SamirMangroliya: Если вы посмотрите на дату ответа, вы заметите, что ей больше 3 лет. Этот пример был написан для Android 2.x, и вам нужно перезагрузить устройство/эмулятор, чтобы запустить будильник. Теперь, для Android 3.1+, даже этого недостаточно - вам нужно запустить операцию до того, как приемник на загрузке будет эффективен. Я бы рекомендовал вам перейти на https://github.com/commonsguy/cw-omnibus/tree/master/AlarmManager/Wakeful, который является одним и тем же базовым проектом, но более актуальным. Запустите его и убедитесь, что он работает (показывает «Toast»), и начнутся тревоги. – CommonsWare

+0

привет, если я вызываю PollReceiver.scheduleAlarms (это); в основном действии, и когда я закрываю приложение, перезапустите (предположим, что через один час я открываю приложение более 15 раз), тогда он создает будильник каждый раз в течение 5 минут? –

2

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

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 = 1000 * 60 * 2; 

    // The minimum time between updates in milliseconds 
    private static final long MIN_TIME_BW_UPDATES = 1000 * 30; // 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> 
Смежные вопросы