¿Es posible ejecutar el servicio en la plataforma android de forma continua incluso después de bloquear el dispositivo?

Hemos estado trabajando en el desarrollo de servicios para la plataforma android.

En nuestro servicio necesitamos enviar datos GPS (Lat y Long) del dispositivo a algún servicio REST externo después de cada minuto.

Está funcionando bien durante casi 15 minutos después del bloqueo del dispositivo. Pero después de eso no envía ningún dato.

Después de desbloquear el dispositivo, comienza de nuevo a enviar datos a través del servicio REST.

Mi código hasta ahora

public class MainActivity extends AppCompatActivity { private PendingIntent pendingIntent; private PowerManager.WakeLock wakeLock; public static final String USER_NAME = "USERNAME"; String username; String password; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent alarm = new Intent(this, AlarmReceiver.class); boolean alarmRunning = (PendingIntent.getBroadcast(this, 0, alarm, PendingIntent.FLAG_NO_CREATE) != null); if(alarmRunning == false) { PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarm, 0); AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), 30000, pendingIntent); } PowerManager mgr = (PowerManager)this.getSystemService(Context.POWER_SERVICE); wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"MyWakeLock"); wakeLock.acquire(); } public class BackgroundService extends Service { private boolean isRunning; private Context context; private Thread backgroundThread; @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { this.context = this; this.isRunning = false; this.backgroundThread = new Thread(myTask); } private Runnable myTask = new Runnable() { public void run() { // Do something here login("admin","admin"); stopSelf(); } }; @Override public void onDestroy() { this.isRunning = false; } @Override public int onStartCommand(Intent intent, int flags, int startId) { if(!this.isRunning) { this.isRunning = true; this.backgroundThread.start(); } return START_STICKY; } private void login(final String strLatitude, final String strLongitude) { class LoginAsync extends AsyncTask<String, Void, String> { String charset = "UTF-8"; HttpURLConnection conn; DataOutputStream wr; StringBuilder result = new StringBuilder(); URL urlObj; JSONObject jObj = null; StringBuilder sbParams; String paramsString; @Override protected void onPreExecute() { super.onPreExecute(); // loadingDialog = ProgressDialog.show(MainActivity.this, "Please wait", "Loading..."); } @Override protected String doInBackground(String... params) { String uname = params[0]; String pass = params[1]; sbParams = new StringBuilder(); try { sbParams.append("name").append("=") .append(URLEncoder.encode(uname, charset)); sbParams.append("&"); sbParams.append("password").append("=") .append(URLEncoder.encode(pass, charset)); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } try { String url="http://192.168.0.122:1234/YegoService.svc/AddVehicleMovement"; URL object=new URL(url); HttpURLConnection con = (HttpURLConnection) object.openConnection(); con.setDoOutput(true); con.setDoInput(true); con.setRequestProperty("Content-Type", "application/json"); con.setRequestProperty("Accept", "application/json"); con.setRequestMethod("POST"); JSONObject parent = new JSONObject(); parent.put("strValidatorID","111"); parent.put("TXT_LAT", "28.25252525"); parent.put("TXT_LONG", "77.7777777"); parent.put("DAT_DATE", ""); con.connect(); OutputStreamWriter wr = new OutputStreamWriter(con.getOutputStream()); wr.write(parent.toString()); wr.flush(); wr.close(); InputStream input = con.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(input)); String line; while ((line = reader.readLine()) != null) { result.append(line); } con.disconnect(); } catch (IOException e) { e.printStackTrace(); } catch (Exception ex) { ex.printStackTrace(); } return result.toString(); } @Override protected void onPostExecute(String result){ String s = result.trim(); } } LoginAsync la = new LoginAsync(); la.execute("admin", "admin"); } } public class AlarmReceiver extends BroadcastReceiver { String strLatitude; String strLongitude; @Override public void onReceive(Context context, Intent intent) { Intent background = new Intent(context, BackgroundService.class); context.startService(background); } } 

¿Qué hacer?

Usted está adquiriendo el bloqueo de la vigilia en su Activity . El problema aquí es que cuando el dispositivo está bloqueado, su Activity se empuja al fondo. Después de 15 minutos de inactividad, Android simplemente está matando el proceso. Esto libera el bloqueo de la estela. El dispositivo se va a dormir.

Ahora, la próxima vez que su alarma se apague, el dispositivo se despierta, su BroadcastReceiver se dispara, onReceive() se llama, inicia su Service , pero entonces el dispositivo vuelve a dormir porque no hay ningún bloqueo, No hace nada.


Otro enfoque, si desea evitar que el teléfono se vaya a dormir mientras la aplicación se está ejecutando, sería adquirir el bloqueo de la sesión en el Service . En este caso, no desea llamar a stopSelf() cada vez que ejecute Runnable . Desea mantener el Service funcionamiento hasta que quiera detenerlo, momento en el que llamaría a stopService() . De esta manera, el Service siempre estaría activo (aunque no esté haciendo nada) y evitaría que el dispositivo durmiera a través del bloqueo de la vigilia. Esto puede, sin embargo, poner un drenaje inaceptable en la batería (usted tendrá que probarlo).

Debe adquirir el bloqueo de retraso en BroadcastReceiver y asegurarse de que el Service se inicia y adquiere un bloqueo de la sesión antes de que el dispositivo vuelva a dormir. Echa un vistazo a WakefulBroadcastReceiver , que puede utilizar para implementar este comportamiento.

Un acercamiento podría ser para que usted confíe en el AlarmManager : una vez que usted suscribe a un AlarmManager el sistema ejecuta su código en el intervalo que usted instala, aunque su app no ​​esté activo. Cada vez que se ejecuta puede decidir procesar algún código … Así que evita completamente la necesidad de mantener un servicio vivo.

Lo que usted necesita es una clase de alarma que manejará la intención de AlarmManager.


Cree su alarma:

 public class Alarm extends BroadcastReceiver { private static final String TAG = "Alarm"; @Override public void onReceive(Context context, Intent intent) { PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, ""); wl.acquire(); /*************** Here you can do your stuff... This will be triggered every second. Send data from here, or better: call an IntentService that will take care of it. ****************/ wl.release(); } public void SetAlarm(Context context) { Intent i = new Intent(context, Alarm.class); boolean alarmUp = (PendingIntent.getBroadcast(context, 0, i, PendingIntent.FLAG_NO_CREATE) != null); if (alarmUp) { // The alarm is already running, do not set it twice } else { AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0); am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000, pi); // 1000 Millisec means it will trigger it every second... and RTC_WAKEUP means that it will wake up your device if needed. } } // later on, use this method if you want to manually cancel the AlarmManager : public void CancelAlarm(Context context) { Intent intent = new Intent(context, Alarm.class); PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0); AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); alarmManager.cancel(sender); } } 

En su Manifiesto declarar esta alarma BroadcastReceiver

 <receiver android:name=".utils.Alarm" android:process=":remote" > </receiver> 

Y desde donde quieras en tu actividad, llama a este AlarmManager.

 Alarm alarm = new Alarm(); @Override protected void onCreate(Bundle savedInstanceState) { alarm.SetAlarm(this); } // or if elsewhere you need to stop the Alarm : alarm.CancelAlarm(this); 

Esta es la idea principal. Ahora usted necesita ocuparse de la pantalla encendido o apagado. Para estas 2 soluciones: puede registrarse para la intención del estado de la pantalla del dispositivo y administrar el AlarmManager activado / desactivado … o puede dejar que el AlarmManager se ejecute siempre, pero comprobando si el dispositivo está encendido / apagado antes de enviar datos …

Espero que esto ayude!

Sí, puede ejecutar cualquier servicio incluso si el dispositivo está bloqueado. Incluso, puede reanudar el servicio después de reiniciar el dispositivo.

Puede implementar GCM Network Manager.

Código de ejemplo requerido: –

 <service android:name=".MyTaskService" android:exported="true" android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE"> <intent-filter> <action android:name="com.google.android.gms.gcm.ACTION_TASK_READY" /> </intent-filter> </service> 

Código Java: –

 mGcmNetworkManager = GcmNetworkManager.getInstance(this); OneoffTask task = new OneoffTask.Builder() .setService(MyTaskService.class) .setTag(TASK_TAG_WIFI) .setExecutionWindow(0L, 3600L) .setRequiredNetwork(Task.NETWORK_STATE_UNMETERED) .build(); mGcmNetworkManager.schedule(task); 

Para obtener más información, puede visitar https://developers.google.com/cloud-messaging/network-manager#run_tasks y leer los documentos.

Sólo tienes que incluir los servicios de gcm en tu proyecto para usar el administrador de red de GCM. Soporte 4.0 +

Acepte esta respuesta si esta es la solución que desea. Esto puede ayudar a otros desarrolladores también.

Sí, puede implementar un servicio de fondo que casi nunca se matará. Pero tienes que declararlo para correr en primer plano. Puede ver lo que dice el sitio para desarrolladores de Android, refiriéndose a esta url ( http://developer.android.com/guide/components/services.html ) también en este artículo ( http://developer.android.com/guide/ Componentes / procesos-y-hilos.html ) dicen,

Hay cinco niveles en la jerarquía de importancia y los diferentes tipos de procesos en orden de importancia (el primer proceso es el más importante y se mata en último lugar):

  1. Proceso de primer plano :

Un proceso que se requiere para lo que el usuario está haciendo actualmente. Se considera que un proceso está en primer plano si se cumplen cualquiera de las condiciones siguientes:

  • Alberga una actividad con la que el usuario interactúa (se ha llamado al método onResume () de la actividad).
  • Alberga un servicio que está vinculado a la actividad con la que el usuario está interactuando.
  • Alberga un servicio que se está ejecutando "en primer plano", el servicio ha llamado startForeground ().
  • Alberga un servicio que está ejecutando una de sus devoluciones de llamada del ciclo de vida (onCreate (), onStart () o onDestroy ()).
  • Alberga un BroadcastReceiver que está ejecutando su método onReceive ().

Generalmente, sólo unos pocos procesos de primer plano existen en un momento dado. Sólo se matan como último recurso, si la memoria es tan baja que no todos pueden seguir corriendo. Generalmente, en ese punto, el dispositivo ha alcanzado un estado de paginación de memoria, por lo que es necesario matar algunos procesos de primer plano para mantener la interfaz de usuario sensible.

Así que usted tiene que comenzar su servicio en primer plano. Para hacer esto usted tiene implementar el servicio como se indica a continuación.

 public class MyForegroundService extends Service { @Override public void onCreate() { super.onCreate(); //your code goes here } @Override public IBinder onBind(Intent intent) { throw new UnsupportedOperationException("Not yet implemented"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { keepServiceAlive(); //your code goes here return(START_NOT_STICKY); } private void keepServiceAlive() { Intent notificationIntent = new Intent(this, MainActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); Notification notification = new NotificationCompat.Builder(this).setContentTitle(getString(R.string.app_name)) .setContentText("Hello") .setSmallIcon(R.mipmap.ic_launcher) .setContentIntent(pendingIntent) .build(); startForeground(Notification.FLAG_ONGOING_EVENT, notification); } @Override public void onDestroy() { super.onDestroy(); Log.w(getClass().getName(), "Got to stop()!"); stopForeground(true); } } 

Gracias y suerte gud ..

Usted tiene que disparar la alarma una y otra vez cuando el servicio se completa la ejecución.

También puede implementar un BroadCastReceiver que inicia el servicio en el arranque del dispositivo.

Compruebe este tutorial: http://ncona.com/2014/04/schedule-your-android-app-to-do-something-periodically/

Tuve el mismo problema en mi aplicación, pero he resuelto mi problema primero crear servicio, utilizar el servicio periódico. Usted puede especificar el límite de tiempo para actualizar los datos. En mi caso, este era el código.

UpdateService.java

 public class UpdateServices extends Service implements LocationListener { String id, latee, longee; // j private ProgressDialog pDialog; ProgressDialog progressDialog; JSONParser jsonParser = new JSONParser(); DBManager db; private static String url_create_locationupdate = "http://192.168.0.175/simple_demo3/classes/create_locationupdate.php"; private static final String TAG_SUCCESS = "success"; public static String LOG = "Log"; private final Context mContext; boolean isGPSEnabled = false; boolean isNetworkEnabled = false; boolean canGetLocation = false; Location location; // location double latitude; // latitude double longitude; // longitude private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 3; // 0 meters private long MIN_TIME_BW_UPDATES; // 10 second private long MIN_LENGTH_BW_UPDATES; SharedPreferences mPref; protected LocationManager locationManager; public UpdateServices(Context context) { this.mContext = context; } public UpdateServices() { super(); mContext = UpdateServices.this; } @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); Log.i(LOG, "Service started"); mPref = getSharedPreferences("mFile", 0); MIN_TIME_BW_UPDATES = mPref.getLong("mint", 1) * 1000 * 60; MIN_LENGTH_BW_UPDATES = mPref.getLong("kmeter", 1) * 1000; Log.i("asd", "This is sparta"); latitude = getLocation().getLatitude(); longitude = getLocation().getLongitude(); return START_STICKY; } @Override public void onCreate() { super.onCreate(); Log.i(LOG, "Service created"); } @Override public void onDestroy() { super.onDestroy(); Log.i(LOG, "Service destroyed"); } public Location getLocation() { try { locationManager = (LocationManager) mContext .getSystemService(LOCATION_SERVICE); isGPSEnabled = locationManager .isProviderEnabled(LocationManager.GPS_PROVIDER); isNetworkEnabled = locationManager .isProviderEnabled(LocationManager.NETWORK_PROVIDER); if (!isGPSEnabled && !isNetworkEnabled) { } else { this.canGetLocation = true; if (isNetworkEnabled) { locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, 5000, MIN_DISTANCE_CHANGE_FOR_UPDATES, this); Log.d("Network", "Network"); if (locationManager != null) { location = locationManager .getLastKnownLocation(LocationManager.NETWORK_PROVIDER); if (location != null) { latitude = location.getLatitude(); longitude = location.getLongitude(); } } } // if GPS Enabled get lat/long using GPS Services if (isGPSEnabled) { if (location == null) { locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this); Log.d("GPS Enabled", "GPS Enabled"); if (locationManager != null) { location = locationManager .getLastKnownLocation(LocationManager.GPS_PROVIDER); if (location != null) { latitude = location.getLatitude(); longitude = location.getLongitude(); } } } } } } catch (Exception e) { e.printStackTrace(); } return location; } @Override public void onLocationChanged(Location location) { // this will be called every second String laty = Double.toString(getLocation().getLatitude()); String lagy = Double.toString(getLocation().getLongitude()); db = new DBManager(mContext); db.open(); db.mInsertGPSCor(laty, lagy); Toast.makeText( getApplicationContext(), "Your Location is - \nLat: " + location.getLatitude() + "\nLong: " + location.getLongitude(), Toast.LENGTH_LONG).show(); Toast.makeText(UpdateServices.this, "record entered", Toast.LENGTH_SHORT).show(); db.close(); // store in server new CreateNewProduct(this).execute(); } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onProviderEnabled(String provider) { } @Override public void onProviderDisabled(String provider) { } class CreateNewProduct extends AsyncTask<String, String, String> { private Context mContext; public CreateNewProduct(Context context) { super(); mContext = context; } @Override protected void onPreExecute() { try { super.onPreExecute(); progressDialog = ProgressDialog.show(mContext, "Press Back to Cancel", "Sending Data to Server..", true, false); } catch (Exception e) { // TODO: handle exception } } /** * Creating product * */ protected String doInBackground(String... args) { List<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("ID", id)); params.add(new BasicNameValuePair("LATITUDE", latee)); params.add(new BasicNameValuePair("LONGITUDE", longee)); JSONObject json = jsonParser.makeHttpRequest( url_create_locationupdate, "POST", params); try { int success = json.getInt(TAG_SUCCESS); if (success == 1) { return "done"; } else { // failed to create product return "fail"; } } catch (JSONException e) { e.printStackTrace(); return "exec"; } } /** * After completing background task Dismiss the progress dialog * **/ protected void onPostExecute(String file_url) { if (progressDialog.isShowing()) progressDialog.dismiss(); if (file_url.equalsIgnoreCase("done")) { show.message(mContext, "uploading successed"); } if (file_url.equalsIgnoreCase("fail") || file_url.equalsIgnoreCase("exec")) { try { show.message(mContext, "uploading failed"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } public void onConnectionSuspended(int arg0) { // TODO Auto-generated method stub } } 

Y Main.java

 public class Main extends Activity { Button btn_startGps, btn_stopGps; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.auto_gps_update); btn_startGps = (Button) findViewById(R.id.button_service); btn_stopGps = (Button) findViewById(R.id.button_stopservice); btn_startGps.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startService(new Intent(About.this, UpdateServices.class)); Toast.makeText(About.this, "Service Started", Toast.LENGTH_SHORT).show(); } }); btn_stopGps.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { stopService(new Intent(About.this, UpdateServices.class)); Log.e("sss", "ddddd"); Toast.makeText(About.this, "Service Stopped", Toast.LENGTH_SHORT).show(); } }); } 

Pero aquí un servicio de problemas no es parar aquí para detener el servicio

Porque tengo regreso

  return START_STICKY; 

En onStartCommand(...)

Lee más en START_STICKY y START_NOT_STICKY

Y documentos oficiales

Si ejecuta la aplicación en la API 21+, utilizar JobScheduler, que se describe en la documentación de Google, también es el mejor enfoque.

Además, si no desea cambiar su estructura de código, puede utilizar su servicio para mantener la CPU encendida incluso si la pantalla está apagada. Lee cómo mantener la CPU encendida desde la documentación de Google. Simplemente agregue el permiso en su manifiesto <uses-permission android:name="android.permission.WAKE_LOCK" /> y en su Service.onCreate , coloque:

 PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE); WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakelockTag"); wakeLock.acquire(); 

Y suelte en wakelock.release() con wakelock.release() . Pero tenga en cuenta que drena la batería. Pero si usted dijo que el dispositivo siempre estará conectado a una fuente de alimentación, creo que no será un problema. Por si acaso, será mejor tener una interfaz de usuario admin en la aplicación para detener el servicio manualmente.

 In Manifest file, <service android:name=".MyService"></service> 

MyService.java

 public class MyService extends Service { @Override public void onCreate() { super.onCreate(); // your code here } @Override public int onStartCommand(Intent intent, int flags, int startId) { return START_STICKY; } @Override public void onDestroy() { super.onDestroy(); Intent it = new Intent(MyService.this, MyService.class); getApplication().startService(it); // If service will destroy, Start the service again } @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } } 

Para ejecutar el servicio, agregue esto a su actividad,

  Intent it = new Intent(getApplication(), MyService.class); getApplicationContext().startService(it); 
  • Android no puede pasar extras de intención aunque AlarmManager
  • Android Broadcast Receiver Error: Clase no encontrada excepción
  • Mover un mensaje a la bandeja de entrada desde la base de datos
  • Android - Extraer texto de SMS
  • La alarma en el AlarmManager se borra cuando se procesa el proceso
  • Servicio de grabación / procesamiento de llamadas! - Android
  • Android receptor SMS no funciona
  • TaskStackBuilder # startActivities () NullPointerException
  • TIMEZONE_CHANGED intención que se recibe cada pocos segundos
  • ¿Por qué BroadcastReceiver funciona incluso cuando la aplicación está en segundo plano?
  • Escuchar el acceso a la ubicación desactivar / activar en la configuración
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.