Arquitectura de Android-Job Desglosada
El diseño central de Android-Job se basa en proporcionar una interfaz de programación uniforme que selecciona automáticamente el mecanismo de programación más adecuado según la versión de Android del dispositivo. Este proceso de selección inteligente se realiza mediante la enumeración JobApi, que contiene todas las APIs de tareas en background disponibles:
- WORK_MANAGER - Implementación mediante WorkManager
- V_26 - JobScheduler para Android 8.0 y superiores
- V_24 - JobScheduler para Android 7.0 y superiores
- V_21 - JobScheduler para Android 5.0 y superiores
- V_19 - AlarmManager para Android 4.4 y superiores
- V_14 - AlarmManager para Android 4.1 y superiores
- GCM - Gestor de comunicación en la nube de Google
Cada JobApi tiene una implementación concreta de JobProxy asociada, organizadas en diferentes paquetes del proyecto:
library/src/main/java/com/evernote/android/job/
├── v14/JobProxy14.java # Implementación para Android 4.1+
├── v19/JobProxy19.java # Implementación para Android 4.4+
├── v21/JobProxy21.java # Implementación para Android 5.0+
├── v24/JobProxy24.java # Implementación para Android 7.0+
├── v26/JobProxy26.java # Implementación para Android 8.0+
├── gcm/JobProxyGcm.java # Implementación mediante GCM
└── work/JobProxyWorkManager.java # Implementación con WorkManager
Implementación de JobProxy Personalizado en 5 Pasos
Paso 1: Comprendiendo la Interfaz JobProxy
JobProxy constituye la clase base abstracta para todos los proxies de plataforma, definiendo cuatro métodos fundamentales que cada implementación debe completar:
public interface JobProxy {
void plantOneOff(JobRequest request); // Programar tarea única
void plantPeriodic(JobRequest request); // Programar tarea periódica
void plantPeriodicFlexSupport(JobRequest request); // Soporte para períodos flexibles
void cancel(int jobId); // Cancelar tarea específica
boolean isPlatformJobScheduled(JobRequest request); // Verificar estado de programación
}
Cada implementación concreta debe proporcionar lógica específica para estos métodos, adaptándose a las características particulares de la plataforma destino.
Paso 2: Analizando los Patrones de Implementación Existentes
Tomando como referencia JobProxy21.java, observamos que está optimizado específicamente para el JobScheduler de Android 5.0 y versionees posteriores:
- Mecanismo de reintento inteligente - Gestión de permisos relacionados con BOOT_COMPLETED
- Programación flexible de tareas - Soporte para ventanas de tiempo precisas y flexibles
- Adaptación al estado de red - Conversión automática de requisitos de tipo de red
- Soporte para tareas transitorias - Manejo de trabajos temporales que no requieren persistencia
Paso 3: Desarrollando una Clase JobProxy Personalizada
Para crear una versión optimizada dirigida a una plataforma de hardware específica, podemos extender la implementación base:
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class OptimizedJobProxy21 extends JobProxy21 {
private static final String LOG_TAG = "OptimizedJobProxy21";
private final Context appContext;
public OptimizedJobProxy21(Context context) {
super(context, LOG_TAG);
this.appContext = context.getApplicationContext();
}
@Override
public void plantOneOff(JobRequest request) {
// Aplicar lógica personalizada para optimización de batería
if (detectPowerSavingEnabled()) {
modificarTareaParaAhorroEnergia(request);
}
// Invocar implementación de la clase padre
super.plantOneOff(request);
}
@Override
protected JobInfo.Builder createBaseBuilder(JobRequest request, boolean allowPersisting) {
JobInfo.Builder constructor = super.createBaseBuilder(request, allowPersisting);
// Aplicar optimizaciones específicas de la plataforma
if (detectarPlataformaHardwareEspecial()) {
constructor.setImportantWhileForeground(true);
constructor.setRequiresStorageNotLow(false);
}
return constructor;
}
private boolean detectPowerSavingEnabled() {
// Verificar si el modo ahorro de energía está activo
PowerManager servicioEnergia = (PowerManager) appContext.getSystemService(Context.POWER_SERVICE);
return servicioEnergia != null && servicioEnergia.isPowerSaveMode();
}
private boolean detectarPlataformaHardwareEspecial() {
// Identificar plataforma de hardware específica
return Build.MANUFACTURER.equals("FabricanteEspecial");
}
}
Paso 4: Integrando el JobProxy Personalizado en el Sistema JobApi
Para utilizar nuestro JobProxy personalizado, necesitamos extender la enumeración JobApi o modificar la lógica de selección de API predeterminada:
public class CustomJobApi {
public static JobApi obtenerApiPredeterminada(Context contexto) {
// Verificar prioritariamente la plataforma de hardware especial
if (detectarPlataformaHardwareEspecial()
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return CUSTOM_V_21;
}
// Retroceder a la lógica de selección estándar
return JobApi.getDefault(contexto);
}
// Valor de enumeración JobApi personalizado
public static final JobApi CUSTOM_V_21 = new JobApi(true, true, false) {
@Override
public boolean isSupported(Context context) {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
&& verificarServicioYPermisos(context, PlatformJobService.class, JOB_SCHEDULER_PERMISSION)
&& detectarPlataformaHardwareEspecial();
}
@NonNull
@Override
JobProxy crearProxy(Context context) {
return new OptimizedJobProxy21(context);
}
};
}
Paso 5: Configuración y Uso del JobProxy Personalizado
Durante la inicialización de la aplicación, configuramos el JobApi personalizado:
public class Aplicacion extends Application {
@Override
public void onCreate() {
super.onCreate();
// Configurar JobManager para utilizar JobApi personalizado
JobConfig.setApiEnabled(JobApi.WORK_MANAGER, false);
JobConfig.setApiEnabled(JobApi.V_21, false);
// Registrar creador de tareas personalizado
JobManager.create(this).addJobCreator(new CreadorTareasDemo());
// Aplicar estrategia de programación optimizada
programarTareasOptimizadas();
}
private void programarTareasOptimizadas() {
// Programar tareas con optimizaciones personalizadas
PersistableBundleCompat datosExtra = new PersistableBundleCompat();
datosExtra.putString("optimizado", "true");
new JobRequest.Builder(SincronizacionDemo.TAG)
.setExecutionWindow(30_000L, 40_000L)
.setBackoffCriteria(5_000L, JobRequest.BackoffPolicy.EXPONENTIAL)
.setRequiresCharging(false)
.setRequiresDeviceIdle(true)
.setRequiredNetworkType(JobRequest.NetworkType.UNMETERED)
.setExtras(datosExtra)
.setUpdateCurrent(true)
.build()
.schedule();
}
}
Técnicas de Optimización Avanzadas
Estrategia de Optimización de Batería
Implemantando gestión inteligente de energía en el JobProxy personalizado:
protected JobInfo.Builder createBaseBuilder(JobRequest request, boolean allowPersisting) {
JobInfo.Builder constructor = super.createBaseBuilder(request, allowPersisting);
// Ajustar prioridad de tareas según estado de batería
BatteryManager managerBateria = (BatteryManager) mContext.getSystemService(Context.BATTERY_SERVICE);
if (managerBateria != null) {
int nivelBateria = managerBateria.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
if (nivelBateria < 20) {
// Reducir frecuencia de tareas cuando batería está baja
constructor.setPeriodic(request.getIntervalMs() * 2);
} else if (nivelBateria > 80) {
// Aumentar prioridad de tareas con batería alta
constructor.setImportantWhileForeground(true);
}
}
return constructor;
}
Adaptación Inteligente de Condiciones de Red
Optimizando la detección de condiciones de red:
protected int convertNetworkType(@NonNull JobRequest.NetworkType tipoRed) {
// Implementar lógica personalizada de detección de red
ConnectivityManager gestorConexiones = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo redActiva = gestorConexiones.getActiveNetworkInfo();
if (redActiva != null && redActiva.isConnected()) {
int tipo = redActiva.getType();
// Optimizar según tipo de conexión real
if (tipo == ConnectivityManager.TYPE_WIFI) {
// WiFi permite requisitos de red más estrictos
return JobInfo.NETWORK_TYPE_UNMETERED;
} else if (tipo == ConnectivityManager.TYPE_MOBILE) {
// Móvil según plan de datos disponible
return tienePlanIlimitado() ? JobInfo.NETWORK_TYPE_ANY : JobInfo.NETWORK_TYPE_UNMETERED;
}
}
// Retroceder a conversión estándar
return super.convertNetworkType(tipoRed);
}
Detección y Adaptación de Características de Plataforma
public class OptimizadorPlataforma {
public static boolean soportaOptimizacionBateria() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
}
public static boolean soportaModoDoze() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
}
public static boolean soportaJobSchedulerExacto() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
}
public static boolean soportaWorkManager() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
}
}
Comparativa de Rendimiento y Prácticas Recomendadas
Comparación de Características entre Plataformas JobProxy
| Característica | JobProxy14 | JobProxy21 | JobProxy26 | JobProxyWorkManager |
|---|---|---|---|---|
| Versión Android mínima | 4.1+ | 5.0+ | 8.0+ | 4.0+ |
| Optimización de batería | ✓ | ✓ | ✓ | |
| Soporte modo Doze | ✓ | ✓ | ✓ | |
| Tareas exactas | ✓ | |||
| Tareas transitorias | ✓ | ✓ | ✓ | |
| Cadenas de tareas | ✓ |
Recomendaciones de Implementación
- Estrategia de adaptación de versiones: Priorizar el uso del JobProxy más reciente, proporcionando degradación elegante para versiones anteriores
- Diseño respetuoso con la batería: Reducir automáticamente la frecuencia y prioridad de tareas cuando el nivel de batería es bajo
- Percepción inteligente de red: Modificar el comportamiento de las tareas según el tipo y calidad de la conexión
- Mecanismo de manejo de errores: Implementar estrategias de recuperación específicas para cada plataforma
- Monitoreo y registro: Documentar la ejecución de tareas para análisis de problemas y optimización de rendimiento