2010-04-02 13 views
68

Estoy en el proceso de crear una aplicación que es similar a la aplicación de SMS integrada.¿Cómo ejecutar siempre un servicio en segundo plano?

Lo que necesito:

  • un servicio que siempre se ejecuta en segundo plano
  • cada 5 minutos. el servicio verifica la ubicación actual del dispositivo y llama a un servicio web
  • si se cumplen ciertos criterios, el servicio debe generar una notificación (al igual que la aplicación de SMS)
  • cuando se hace clic en la notificación, el usuario la aplicación (al igual que la aplicación SMS)
  • cuando la aplicación se instala el servicio debe iniciarse
  • cuando se reinicia el dispositivo, el servicio debe iniciarse

lo que he intentado:
- ejecutando un servicio regular que funcionó bien hasta que Android mata el servicio
- usando el AlarmManager para hacer los 5 min. llamada de intervalo a un servicio. Pero no pude hacer que esto funcione.

Respuesta

26

Una de mis aplicaciones hace algo muy similar. Para reactivar el servicio después de un período determinado recomiendo postDelayed()

tienen un campo manejador:

private final Handler handler = new Handler(); 

y un repaso Runnable

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

Puede disparar sus notificaciones en el ejecutable.

En la construcción de servicios, y después de cada ejecución empezar así:

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

En onDestroy() retirar el anuncio

handler.removeCallbacks(refresher); 

Para iniciar el servicio en tiempo de arranque que necesita un motor de arranque automático. Esto va en el manifiesto

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

y la ServiceAutoStarter se ve así:

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

parando el sistema operativo de matar el servicio es complicado. Además, su aplicación puede tener un RuntimeException y bloquearse, o su lógica puede bloquearse.

En mi caso, pareció ayudar a actualizar siempre el servicio en pantalla con un BroadcastReceiver. Entonces, si la cadena de actualizaciones se detiene, resucitará cuando el usuario use su teléfono.

En el servicio:

private BroadcastReceiver screenOnReceiver; 

En su servicio onCreate()

screenOnReceiver = new BroadcastReceiver() { 

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

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

A continuación, anular el registro su servicio en onDestroy() con

unregisterReceiver(screenOnReceiver); 
+1

normalmente me gusta sus respuestas, pero este ... no tanto. :-(Por ejemplo, está proponiendo que el servicio registre un receptor para que se resucite una vez asesinado. El receptor será asesinado junto con el servicio, por lo tanto, esto no debería tener ningún efecto. Además, todo el concepto de un servicio eterno es horrible en Android y es la razón por la que los usuarios están luchando con asesinos de tareas o la pantalla Servicios en ejecución en la aplicación Configuración. Hay muy pocos casos en los que se necesita un servicio verdaderamente duradero; la gran mayoría de las veces, 'AlarmManager' será suficiente. – CommonsWare

+4

Gracias CWare, probablemente debería haber aclarado que el resurrector debe protegerse contra fallas lógicas y las muchas cosas que pueden detener la cadena de eventos que activan el servicio, ya que lo que se atribuye al cierre del sistema del sistema a menudo puede ser otra cosa Examinaré el enfoque del gestor de alarmas, recuerdo vagamente haber intentado esto hace algún tiempo y no poder hacerlo funcionar. –

31

un servicio que siempre se está ejecutando en 012.el fondo

Ésta es not possible en ningún sentido real del término, como lo han descubierto. También es bad design.

cada 5 min. el servicio comprueba la ubicación actual del dispositivo y llama a un servicio web

Uso AlarmManager.

usando AlarmManager make el 5 min. llamada de intervalo a un servicio. Pero I no fue capaz de hacer que esto funcione.

Aquí es una sample project que muestra cómo utilizar una, junto con el uso de WakefulIntentService para que pueda permanecer despierto mientras tratando de hacer todo el asunto servicio Web.

Si tiene problemas continuos, abra una nueva pregunta acerca de las cosas específicas que encuentra con AlarmManager que le están causando dolor.

+0

utilicé este proyecto de ejemplo e incluí el log y esperé 10 minutos. ¿Nada funciona? tengo que llamar a cualquier servicio para iniciarlo? –

+2

@SamirMangroliya: Si mira la fecha en la respuesta, notará que tiene más de 3 años. Este ejemplo se escribió para Android 2.x, y necesitaría reiniciar el dispositivo/emulador para iniciar las alarmas. Ahora, para Android 3.1+, incluso eso es insuficiente: debe ejecutar una actividad antes de que el receptor en arranque sea efectivo. Le recomendaría que cambie a https://github.com/commonsguy/cw-omnibus/tree/master/AlarmManager/Wakeful, que es el mismo proyecto básico, pero está más actualizado. Ejecútelo y asegúrese de que la actividad se ejecuta (muestra un "Toast") y las alarmas comenzarán. – CommonsWare

+0

hola si llamo a PollReceiver.scheduleAlarms (esto); en la actividad principal y cuando cierro la aplicación, luego reinicio (supongamos que en una hora abro la aplicación más de 15 veces) y luego ¿crea alarma cada vez durante 5 minutos? –

2

Usted puede hacer esto por algún implementación simple:

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

} 

Usted puede iniciar el servicio por esto:

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

en el manifiesto:

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