android - example - JobScheduler: control de la demora de las restricciones que se cumplen a la tarea que se está ejecutando
jobscheduler android example (1)
Un planificador de trabajos es programar trabajos: activarse periódicamente, con retraso o con restricciones a otros trabajos. Si desea despedir un trabajo al instante, no necesita ser programado, simplemente ejecútelo.
ConnectivityManager cm =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = cm.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnectedOrConnecting()) {
// If there is connectivity, Launch the job directly here
} else {
PersistableBundle extras = new PersistableBundle();
extras.putInt("anExtraInt", someInt);
int networkConstraint = useUnmetered ?
JobInfo.NETWORK_TYPE_UNMETERED : JobInfo.NETWORK_TYPE_ANY;
ComponentName componentName = new ComponentName(context,MyJobService.class);
JobInfo jobInfo = new JobInfo.Builder(jobId, componentName)
.setRequiredNetworkType(networkConstraint)
.setExtras(extras)
.build();
JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(jobInfo);
}
Estoy usando JobScheduler para programar trabajos. Principalmente lo estoy usando para el método .setRequiredNetworkType()
, que le permite especificar que solo desea que el trabajo se programe cuando se establece una conexión de red (o más específicamente una conexión sin medidor).
Estoy usando el siguiente código bastante sencillo para programar mis trabajos:
PersistableBundle extras = new PersistableBundle();
extras.putInt("anExtraInt", someInt);
int networkConstraint = useUnmetered ? JobInfo.NETWORK_TYPE_UNMETERED : JobInfo.NETWORK_TYPE_ANY;
ComponentName componentName = new ComponentName(context, MyJobService.class);
JobInfo jobInfo = new JobInfo.Builder(jobId, componentName)
.setRequiredNetworkType(networkConstraint)
.setExtras(extras)
.build();
JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(jobInfo);
Así que solo hay una restricción en la programación: una conexión de red (que puede ser ''cualquiera'' o ''sin medidor'').
Versión corta de la pregunta.
¿Cómo especifico un retraso máximo de todas las restricciones que se cumplen, y realmente ejecutan el trabajo, por ejemplo, "ejecute el trabajo dentro de los 2 segundos de haber una conexión de red"?
Versión más larga (con divagaciones)
El problema
Lo que estoy descubriendo es que en algunos dispositivos, si un trabajo se programa durante un período en el que la restricción de la red ya está satisfecha , el trabajo se ejecutará inmediatamente (o lo suficientemente rápido como para que el usuario lo perciba).
Pero en otros dispositivos, incluso si ya hay disponible una conexión de red adecuada (para que el trabajo pueda ejecutarse de inmediato), existe un retraso significativo antes de que se ejecute. Entonces, si esto es en respuesta a una acción del usuario, la impresión es que no ha pasado nada y que la aplicación no funciona.
Ahora, soy muy consciente de que esta es probablemente la intención de JobScheduler
... que depende del sistema programar el trabajo para que se ajuste mejor a otras demandas, y que no hay garantía de que el trabajo se ejecutará de inmediato cuando todos Se cumplen las restricciones.
Pero sería bueno poder tener algún control sobre él, cuando sea necesario. Por lo tanto, para los trabajos que se realizan de manera programada, sin la participación del usuario, otorgar al sistema un control completo sobre el tiempo preciso es bueno y bueno.
Pero donde el trabajo es en respuesta a una acción del usuario, quiero que el trabajo se ejecute sin demora ... asumiendo que la conexión de red está ahí. (Si no hay conexión, se puede mostrar un mensaje de que la acción ocurrirá cuando se restaure una conexión de red, y el JobScheduler
se encarga de garantizar que el trabajo se ejecute cuando se restaura la red).
¿SetOverrideDeadline () no es una solución?
Puedo ver que JobInfo.Builder
tiene un método setOverrideDeadline()
, que es casi lo que quiero. Pero eso especifica el retraso máximo desde el momento en que se programa el trabajo (es decir, ejecutar el trabajo en 10 segundos, incluso si no se cumplen todas las restricciones), y no desde cuándo se han cumplido todas las restricciones (es decir, ejecutar el trabajo dentro de los 10 segundos posteriores a la ejecución). restricciones satisfechas).
EDIT: y parece que hay un error molesto que puede hacer que el trabajo se ejecute dos veces cuando se usa setOverrideDeadline()
: vea here y here .
¿Qué pasa con Firebase JobDispatcher?
Veo que Firebase JobDispatcher tiene un disparador Trigger.NOW ("significa que el trabajo debe ejecutarse tan pronto como se cumplan las restricciones de tiempo de ejecución"). ¿Quizás ese es el camino a seguir si JobScheduler
no admite esto de forma nativa? Firebase JobDispatcher me ha desanimado porque parece que está utilizando un martillo para romper una tuerca ... y parece que Firebase se trata de mensajes en la nube, etc., que está muy lejos de la programación de tareas locales (que debería ser una preocupación enteramente local). Y parece que requiere los servicios de Google Play, que de nuevo parece completamente innecesario para la programación de tareas locales. Además, si es posible JobScheduler
de forma inmediata con Firebase, y Firebase solo usa JobScheduler
para Android L +, entonces seguramente debe ser posible hacerlo directamente con JobScheduler
sin depender de Firebase.
EDITAR: Ahora he intentado esto, e incluso Trigger.NOW
no garantiza una respuesta inmediata ... de hecho, estoy descubriendo que hay un retraso de casi exactamente 30 segundos en mi dispositivo, lo cual es extraño.
Fallando en eso...
En la actualidad, la única manera que puedo ver para garantizar la ejecución inmediata (si se cumplen las restricciones) es no usar JobScheduler
.
O tal vez realice la comprobación de restricciones inicial manualmente y ejecute el trabajo con un setOverrideDeadline()
de 0 si se cumplen todas las restricciones; de lo contrario, ejecútelo sin setOverrideDeadline()
.
Parecería mucho más preferible tener la capacidad de controlar el tiempo de JobScheduler
, un poco como se puede con el método setWindow()
de AlarmManager
.