studio proveedor google eventos calendario aplicacion apis agenda java android android-service alarmmanager

java - google - proveedor de calendario android



Cómo el calendario de Google o Instagram hacen que sus aplicaciones funcionen todo el tiempo, incluso después de que se detenga la fuerza (6)

Bueno, para empezar, tienen un sistema de planificación de trabajos que programa los trabajos para que se ejecuten, estos trabajos se pueden detener, iniciar o reanudar. Implementan un mecanismo para detectar fallas, piense en el java-script donde, si una aplicación falla, se puede reiniciar (nodemon o para siempre), en android hay servicios que pueden iniciarse o reanudarse. Existe un comportamiento de servicio especial para reiniciar los servicios bloqueados. .

START_REDELIVER_INTENT- le dice al sistema que reinicie el servicio después de la falla y que vuelva a entregar los intentos que estaban presentes en el momento de la falla.

La versión de Android 5.0 Lollipop (API 21) introduce una API del programador de trabajos a través de la clase JobScheduler. Esta API permite realizar trabajos por lotes cuando el dispositivo tiene más recursos disponibles. En general, esta API se puede utilizar para programar todo lo que no es crítico para el usuario.

También puede combinar alarmas, receptores de difusión y subprocesos junto con programación reactiva para realizar el trabajo. Las alarmas (basadas en la clase AlarmManager) le permiten realizar operaciones basadas en el tiempo fuera de la vida útil de su aplicación. Por ejemplo, podría usar una alarma para iniciar una operación de larga duración, como iniciar un servicio una vez al día para descargar un pronóstico del tiempo.

Puede adjuntar observables a ciertas tareas que realizan operaciones específicas. Puede implementar i / o asíncronas, operaciones computacionales o incluso flujos de datos "infinitos" al diseñar su propio observable.

Parece que forzar la detención debería evitar que la aplicación se ejecute e incluso deshabilitar todas las alarmas de la aplicación. Sin embargo, encontré que la notificación en el calendario de Google todavía se muestra bien incluso después de la detención forzada, y todo el tiempo veo que se ejecuta la aplicación de Instagram, incluso cuando la mato, simplemente se reinicia automáticamente y está nuevamente allí.

Entonces, ¿cuál es una manera de hacer que la aplicación se ejecute constantemente? Estoy haciendo la aplicación con recordatorios y necesito mostrar notificaciones en un tiempo específico, sin importar cómo se cerró la aplicación anteriormente.


De acuerdo con mi conocimiento limitado, necesita usar AlarmManager , WakefulBroadcastReceiver y crear un Service o IntentService para todas estas tareas en segundo plano. Lea más sobre esto here . Tengo un servicio que utilicé para mi aplicación de mensajería Firebase y funciona bien incluso después de que el usuario eliminó la aplicación. En mi caso, me conecto a Firebase en un período fijo utilizando el siguiente servicio.

Primero, tengo la siguiente clase para configurar el AlarmManager .

public class FirebaseHandler { private Context context; private static final long FIREBASE_ALARM_CYCLE_TIME = 300000; // constructors public FirebaseHandler(Context context) { this.context = context; } // set alarm public void setAlarm() { // create pending intent Intent intent = new Intent(context, AlarmReceiver.class); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); final PendingIntent pendingIntent = PendingIntent.getBroadcast( context, AlarmReceiver.ALARM_REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT); // create alarm AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); alarm.setInexactRepeating( AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + FIREBASE_ALARM_CYCLE_TIME, FIREBASE_ALARM_CYCLE_TIME, pendingIntent); } }

Acabo de iniciar esto llamando al new FirebaseHandler(getApplicationContext()).setAlarm() en algún lugar de la actividad. La clase AlarmReceiver es la siguiente.

public class AlarmReceiver extends WakefulBroadcastReceiver { public static final int ALARM_REQUEST_CODE = 12345; @Override public void onReceive(Context context, Intent wakefulIntent) { Intent intent = new Intent(context, FirebaseAlarmService.class); startWakefulService(context, intent); } }

La clase FirebaseAlarmService es la siguiente.

public class FirebaseAlarmService extends Service { private static final String CLASSNAME = FirebaseAlarmService.class.getSimpleName(); private HandlerThread handlerThread; // onStartCommand @Override public int onStartCommand(final Intent intent, int flags, final int startId) { // start a new thread // this depends on your need. I need to do a continuous operation for some time // you can use IntentService too handlerThread = new HandlerThread(CLASSNAME); handlerThread.start(); Handler handler = new Handler(handlerThread.getLooper()); Runnable runnable = new Runnable() { @Override public void run() { // all your codes here for the background task... // remember to release the wake lock and stop service AlarmReceiver.completeWakefulIntent(wakefulIntent); stopSelf(); } return START_NOT_STICKY; } // this is the part that does the trick @Override public void onTaskRemoved(Intent rootIntent) { super.onTaskRemoved(rootIntent); // when the service is killed, start it again new FirebaseHandler(getApplicationContext()).setAlarm(); } // onDestroy @Override public void onDestroy() { super.onDestroy(); // make sure to quit the thread handlerThread.quit(); } }

En resumen, FirebaseHandler establece un AlarmManager , que llamará a WakefulBroadcastReceiver periódicamente, lo que iniciará un Service periódicamente. Cuando AlarmManager el servicio, el servicio iniciará nuevamente el AlarmManager onTaskRemoved .

En AndroidManifest , deberá agregar el siguiente permiso para el bloqueo de activación.

<uses-permission android:name="android.permission.WAKE_LOCK" />

También recuerda añadir el receptor.

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

BONIFICACIÓN: es posible que desee iniciar el servicio una vez que se reinicie el teléfono o se actualice la aplicación a través de PlayStore. Crea otro WakefulBroadcastReceiver .

public class BootBroadcastReceiver extends WakefulBroadcastReceiver { @Override public void onReceive(Context context, Intent wakefulIntent) { // check if user is login, then set the alarm if (isLogin) { new FirebaseHandler(context).setAlarm(); } // remove wake lock WakefulBroadcastReceiver.completeWakefulIntent(wakefulIntent); } }

En el AndroidManifest , agregue el permiso requerido.

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

Añade el filtro de intención.

<receiver android:name=".receiver.BootBroadcastReceiver"> <intent-filter> <!-- get notified on reboot --> <action android:name="android.intent.action.BOOT_COMPLETED" /> <!-- get notified on app updated --> <action android:name="android.intent.action.MY_PACKAGE_REPLACED" /> </intent-filter> </receiver>

CONSEJOS: A veces encontrará que el método anterior no funcionará. En general, esto no es tu culpa. Es la configuración de seguridad del teléfono la que causó esto, especialmente los teléfonos Mi. El usuario deberá "confiar" en la aplicación y habilitar el "inicio automático" en la configuración del teléfono, entonces todo debería funcionar bien.


La visualización de notificaciones es una funcionalidad común de los Servicios de Android y ya hay muchas preguntas sobre cómo evitar que los Servicios se detengan o que se cierren.

Las preguntas relevantes se enumeran a continuación:

Android: ¿Cómo reiniciar automáticamente la aplicación después de que se haya "forzado a cerrar"?

Cómo evitar que el servicio de Android se mate (Servicio con notificación)

¿Cómo reiniciar un servicio en Android?

Mantener el servicio en funcionamiento

Reinicie el servicio incluso si la aplicación se detiene por la fuerza y ​​siga ejecutando el servicio en segundo plano incluso después de cerrar la aplicación ¿Cómo?

Para resumirlos, el primer paso es implementar un BroadcastReceiver que escuche a BOOT_COMPLETED . Esto significará que su servicio se activará cuando se encienda el dispositivo Android. Para hacer esto, pones el siguiente código en el manifiesto:

<receiver android:name=".MyBootCompletedReceiver"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"/> </intent-filter> </receiver>

Asegúrese también de incluir el permiso de arranque completado:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

Luego implementa el BroadcastReceiver:

public class MyBootCompletedReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Intent myService = new Intent(context, MyLongRunningService.class); context.startService(myService); } }

Cuando inicie el Servicio, puede devolver START_STICKY que le indicará al sistema operativo Android que reinicie el servicio si el sistema operativo lo aplasta en condiciones de recursos limitados:

public class MyLongRunningService extends Service { @Override public void onCreate() { super.onCreate(); //inject dependencies if necessary } public int onStartCommand(Intent intent, int flags, int startId) { //setup, then return START_STICKY; } }

En general, los servicios iniciados por aplicaciones serán detenidos por el sistema operativo Android cuando el dispositivo tenga pocos recursos. La devolución de START_STICKY le indica al sistema operativo que reinicie el servicio si es necesario detenerlo. Por lo tanto, al garantizar que el Servicio se inicie cuando se encienda el dispositivo y al solicitar que se reinicie si se detiene en condiciones de bajos recursos, se ha creado un Servicio que se ejecuta constantemente.

Este es el patrón más básico para garantizar que su Servicio (y, por lo tanto, la Aplicación) se ejecute todo el tiempo, lo cual era su requisito.

Hay medidas adicionales además de lo que puede tomar que se describen en las otras respuestas aquí, pero deben considerarse como un complemento a la implementación de un Servicio que comienza en BOOT_COMPLETED y que las solicitudes se reinician si se detiene en condiciones de bajos recursos. .


Si inicia un servicio en la Clase de Aplicación, su servicio siempre se ejecutará, aunque si un usuario termina o fuerza la detención del administrador de tareas, se ejecutará nuevamente.

Para crear un servicio específicamente en Android studio, haga clic con el botón derecho en la aplicación de Project Explorer y luego en Nuevo> Servicio> Servicio

Crear un servicio:

public class ServiceName extends Service { @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { // do your jobs here return super.onStartCommand(intent, flags, startId); } }

Ahora cree una clase de aplicación e inicie el servicio en la clase de aplicación

public class App extends Application { @Override public void onCreate() { super.onCreate(); startService(new Intent(this, ServiceName.class)); } }


Solo para agregar con la respuesta de Sagar Damani, se requiere una llamada de servicio para ejecutar su operación larga en segundo plano, pero también se ejecutan en procesos separados. Cuando declare un servicio o una actividad en androidMenifes.xml, también agregue el atributo android: process = "". Por lo tanto, siempre será persistente si el usuario mata / fuerza la actividad.


Veo dos opciones allí.

La primera es manejar cualquier excepción a través de Thread.setDefaultUncaughtExceptionHandler() que se envía con Java, no es del SDK de Android.

Para ser conciso, haga que su clase de Application personalizada implemente UncaughtExceptionHandler y la registre como oyente ante cualquier excepción en la aplicación. Tan pronto como ocurra un bloqueo, se devolverá la devolución de llamada desde donde puede retrasar un trabajo en el futuro cercano (por ejemplo, generar AlarmManager para iniciar la aplicación nuevamente en 50 ms).

La segunda opción es que puede iniciar sus componentes en diferentes procesos. De los docs :

android: proceso

El nombre del proceso donde se va a ejecutar el servicio. Normalmente, todos los componentes de una aplicación se ejecutan en el proceso predeterminado creado para la aplicación. Tiene el mismo nombre que el paquete de la aplicación. El atributo de proceso del elemento puede establecer un valor predeterminado diferente para todos los componentes. Pero los componentes pueden anular el valor predeterminado con su propio atributo de proceso , lo que le permite distribuir su aplicación en múltiples procesos.

Un bloqueo que ocurre en un proceso diferente no hará que el proceso que hospeda su IU se bloquee.