servicios - servicio siempre activo android studio
Cómo ejecutar siempre un servicio en segundo plano? (4)
Estoy en el proceso de crear una aplicación que es similar a la aplicación de SMS integrada.
Lo que necesito:
- un servicio que siempre se ejecuta en segundo plano
- cada 5 min. 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, se lleva al usuario a la aplicación (al igual que la aplicación de SMS)
- cuando se instala la aplicación, se debe iniciar el servicio
- cuando se reinicia el dispositivo, se debe iniciar el servicio
Lo que he intentado:
- ejecutar 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.
un servicio que siempre se ejecuta en segundo plano
Esto no es posible en ningún sentido real del término, como has descubierto. También es un mal diseño .
cada 5 min. el servicio verifica la ubicación actual del dispositivo y llama a un servicio web
Use AlarmManager
.
usando el AlarmManager haga los 5 min. llamada de intervalo a un servicio. Pero no pude hacer que esto funcione.
Aquí hay un proyecto de muestra que muestra cómo usar uno, junto con el uso de WakefulIntentService
para que se mantenga despierto mientras intenta hacer todo el servicio web.
Si continúa teniendo problemas, abra una nueva pregunta sobre las cosas específicas que se encuentra con AlarmManager
que le AlarmManager
dolor.
Puede hacerlo mediante una 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 = 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();
}
}
Puede comenzar el servicio de esta manera:
/*--Start Service--*/
startService(new Intent(Splash.this, LocationTrace.class));
En 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>
Una de mis aplicaciones hace algo muy similar. Para reactivar el servicio después de un período determinado, recomiendo postDelayed()
Tener un campo de controlador:
private final Handler handler = new Handler();
y un refrescante Runnable
private final Runnable refresher = new Runnable() {
public void run() {
// some action
}
};
Puede disparar sus Notificaciones en el ejecutable.
En la construcción del servicio, y después de cada ejecución, comienza así:
handler.postDelayed(refresher, /* some delay in ms*/);
En onDestroy()
eliminar la publicación
handler.removeCallbacks(refresher);
Para iniciar el servicio en el arranque, necesita un autoarranque. Esto va en tu manifiesto
<receiver android:name="com.example.ServiceAutoStarter">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
y ServiceAutoStarter
ve así:
public class ServiceAutoStarter extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, UpdateService.class));
}
}
Detener el sistema operativo de matar el servicio es complicado. Además, su aplicación puede tener una RuntimeException
y fallar, o su lógica puede paralizarse.
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, onDestroy()
el registro de su servicio en onDestroy()
con
unregisterReceiver(screenOnReceiver);
con estos tres pasos, puede reactivar cada 5 minutos la mayoría de los dispositivos Android:
1. configure su AlarmManager alternativo para diferentes 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. construye tu propio BroadcastReceiver estático:
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. agregue <receiver>
a AndroidManifest.xml
:
<receiver android:name=".OwnReceiver" />