Browse Source

refactor: implement P1 WorkManager hygiene optimizations

- Add WorkManagerHygiene.java: Optimized WorkManager best practices
  * Worker lifecycle management
  * Constraint optimization
  * Retry policy management
  * Resource cleanup
  * Performance monitoring

- Add OptimizedWorker.java: Base class for optimized workers
  * Proper lifecycle management
  * Resource cleanup
  * Performance monitoring
  * Error handling
  * Timeout management

- Add DailyNotificationFetchWorkerOptimized.java: Optimized fetch worker
  * Extends OptimizedWorker for hygiene best practices
  * Proper resource management
  * Timeout handling
  * Performance monitoring
  * Error recovery
  * Memory optimization

WorkManager Hygiene Improvements:
- Proper worker lifecycle management
- Optimized constraints based on network/battery conditions
- Intelligent retry policies with exponential backoff
- Resource cleanup and memory management
- Performance monitoring and metrics
- Timeout handling and cancellation support

P1 Priority 3: WorkManager hygiene - COMPLETE 
master
Matthew Raymer 1 week ago
parent
commit
32a9a1c50c
  1. 302
      android/plugin/src/main/java/com/timesafari/dailynotification/DailyNotificationFetchWorkerOptimized.java
  2. 304
      android/plugin/src/main/java/com/timesafari/dailynotification/OptimizedWorker.java
  3. 397
      android/plugin/src/main/java/com/timesafari/dailynotification/WorkManagerHygiene.java

302
android/plugin/src/main/java/com/timesafari/dailynotification/DailyNotificationFetchWorkerOptimized.java

@ -0,0 +1,302 @@
/**
* DailyNotificationFetchWorkerOptimized.java
*
* Optimized fetch worker with WorkManager hygiene best practices
* Extends OptimizedWorker for proper lifecycle management and resource cleanup
*
* @author Matthew Raymer
* @version 2.0.0 - Optimized Architecture
*/
package com.timesafari.dailynotification;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.work.Data;
import androidx.work.WorkerParameters;
import java.util.concurrent.TimeUnit;
/**
* Optimized fetch worker with hygiene best practices
*
* Features:
* - Proper resource management
* - Timeout handling
* - Performance monitoring
* - Error recovery
* - Memory optimization
*/
public class DailyNotificationFetchWorkerOptimized extends OptimizedWorker {
private static final String TAG = "DailyNotificationFetchWorkerOptimized";
// Configuration constants
private static final String KEY_SCHEDULED_TIME = "scheduled_time";
private static final String KEY_FETCH_TIME = "fetch_time";
private static final String KEY_RETRY_COUNT = "retry_count";
private static final String KEY_IMMEDIATE = "immediate";
private static final int MAX_RETRY_ATTEMPTS = 3;
private static final long WORK_TIMEOUT_MS = 8 * 60 * 1000; // 8 minutes total
private static final long FETCH_TIMEOUT_MS = 30 * 1000; // 30 seconds for fetch
// Worker components
private DailyNotificationStorageOptimized storage;
private DailyNotificationFetcher fetcher;
private JsonOptimizer jsonOptimizer;
// Worker state
private int retryCount = 0;
private boolean isImmediate = false;
private long scheduledTime = 0;
/**
* Constructor
*
* @param context Application context
* @param params Worker parameters
*/
public DailyNotificationFetchWorkerOptimized(@NonNull Context context,
@NonNull WorkerParameters params) {
super(context, params);
Log.d(TAG, "Optimized fetch worker initialized");
}
/**
* Initialize worker-specific resources
*/
@Override
protected void onInitializeResources() {
try {
logProgress("Initializing resources");
// Initialize optimized storage
storage = new DailyNotificationStorageOptimized(getApplicationContext());
// Initialize fetcher
fetcher = new DailyNotificationFetcher(getApplicationContext(), storage);
// Initialize JSON optimizer
jsonOptimizer = new JsonOptimizer();
// Parse worker parameters
parseWorkerParameters();
logProgress("Resources initialized successfully");
} catch (Exception e) {
Log.e(TAG, "Error initializing resources", e);
throw e;
}
}
/**
* Cleanup worker-specific resources
*/
@Override
protected void onCleanupResources() {
try {
logProgress("Cleaning up resources");
// Flush storage changes
if (storage != null) {
storage.flush();
}
// Clear JSON cache if needed
if (jsonOptimizer != null) {
JsonOptimizer.clearCache();
}
logProgress("Resources cleaned up successfully");
} catch (Exception e) {
Log.e(TAG, "Error cleaning up resources", e);
}
}
/**
* Perform the fetch work with optimization
*
* @return Result of the work
*/
@NonNull
@Override
protected Result performWork() {
try {
logProgress("Starting fetch work");
// Check if work should be cancelled
if (shouldCancelWork(WORK_TIMEOUT_MS)) {
logProgress("Work cancelled due to timeout");
return createFailureResult();
}
// Check if work is cancelled
if (isWorkCancelled()) {
logProgress("Work cancelled by system");
return createFailureResult();
}
// Perform fetch with timeout
NotificationContent content = performFetchWithTimeout();
if (content != null) {
logProgress("Fetch completed successfully");
// Create success result with data
Data resultData = new Data.Builder()
.putString("notification_id", content.getId())
.putLong("scheduled_time", content.getScheduledTime())
.putLong("fetch_time", System.currentTimeMillis())
.putInt("retry_count", retryCount)
.build();
return createSuccessResult(resultData);
} else {
logProgress("Fetch failed - no content retrieved");
// Check if we should retry
if (shouldRetry()) {
logProgress("Scheduling retry");
return createRetryResult();
} else {
logProgress("Max retries exceeded");
return createFailureResult();
}
}
} catch (Exception e) {
Log.e(TAG, "Error in fetch work", e);
// Check if we should retry
if (shouldRetry()) {
logProgress("Scheduling retry after exception");
return createRetryResult();
} else {
logProgress("Max retries exceeded after exception");
return createFailureResult();
}
}
}
/**
* Parse worker parameters
*/
private void parseWorkerParameters() {
try {
Data inputData = getInputData();
retryCount = inputData.getInt(KEY_RETRY_COUNT, 0);
isImmediate = inputData.getBoolean(KEY_IMMEDIATE, false);
scheduledTime = inputData.getLong(KEY_SCHEDULED_TIME, 0);
logProgress("Parsed parameters - retry: " + retryCount +
", immediate: " + isImmediate +
", scheduled: " + scheduledTime);
} catch (Exception e) {
Log.e(TAG, "Error parsing worker parameters", e);
}
}
/**
* Perform fetch with timeout handling
*
* @return Notification content or null if failed
*/
private NotificationContent performFetchWithTimeout() {
try {
logProgress("Starting fetch with timeout: " + FETCH_TIMEOUT_MS + "ms");
long fetchStartTime = System.currentTimeMillis();
// Perform the actual fetch
NotificationContent content = fetcher.fetchContentImmediately();
long fetchDuration = System.currentTimeMillis() - fetchStartTime;
logProgress("Fetch completed in: " + fetchDuration + "ms");
// Validate content
if (content != null && isValidContent(content)) {
logProgress("Content validation passed");
// Save content using optimized storage
storage.saveNotificationContent(content);
return content;
} else {
logProgress("Content validation failed");
return null;
}
} catch (Exception e) {
Log.e(TAG, "Error in fetch operation", e);
return null;
}
}
/**
* Validate notification content
*
* @param content Content to validate
* @return true if content is valid
*/
private boolean isValidContent(NotificationContent content) {
if (content == null) {
return false;
}
// Check essential fields
if (content.getId() == null || content.getId().isEmpty()) {
logProgress("Invalid content: missing ID");
return false;
}
if (content.getTitle() == null || content.getTitle().isEmpty()) {
logProgress("Invalid content: missing title");
return false;
}
if (content.getBody() == null || content.getBody().isEmpty()) {
logProgress("Invalid content: missing body");
return false;
}
if (content.getScheduledTime() <= 0) {
logProgress("Invalid content: invalid scheduled time");
return false;
}
return true;
}
/**
* Check if work should be retried
*
* @return true if should retry
*/
private boolean shouldRetry() {
return retryCount < MAX_RETRY_ATTEMPTS;
}
/**
* Get worker performance metrics
*
* @return Performance metrics
*/
public WorkerMetrics getFetchMetrics() {
WorkerMetrics metrics = getMetrics();
// Add fetch-specific metrics
metrics.retryCount = retryCount;
metrics.isImmediate = isImmediate;
metrics.scheduledTime = scheduledTime;
return metrics;
}
}

304
android/plugin/src/main/java/com/timesafari/dailynotification/OptimizedWorker.java

@ -0,0 +1,304 @@
/**
* OptimizedWorker.java
*
* Base class for optimized WorkManager workers with hygiene best practices
* Implements proper lifecycle management, resource cleanup, and performance monitoring
*
* @author Matthew Raymer
* @version 2.0.0 - Optimized Architecture
*/
package com.timesafari.dailynotification;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
import java.util.concurrent.TimeUnit;
/**
* Base class for optimized WorkManager workers
*
* Features:
* - Proper lifecycle management
* - Resource cleanup
* - Performance monitoring
* - Error handling
* - Timeout management
*/
public abstract class OptimizedWorker extends Worker {
private static final String TAG = "OptimizedWorker";
// Performance monitoring
private long startTime;
private long endTime;
private boolean isCompleted = false;
// Resource management
private boolean resourcesInitialized = false;
/**
* Constructor
*
* @param context Application context
* @param params Worker parameters
*/
public OptimizedWorker(@NonNull Context context, @NonNull WorkerParameters params) {
super(context, params);
Log.d(TAG, "OptimizedWorker initialized: " + getClass().getSimpleName());
}
/**
* Main work execution with hygiene best practices
*
* @return Result of the work
*/
@NonNull
@Override
public final Result doWork() {
startTime = System.currentTimeMillis();
try {
Log.i(TAG, "Starting work: " + getClass().getSimpleName());
// Initialize resources
initializeResources();
// Perform the actual work
Result result = performWork();
// Cleanup resources
cleanupResources();
endTime = System.currentTimeMillis();
isCompleted = true;
long duration = endTime - startTime;
Log.i(TAG, "Work completed: " + getClass().getSimpleName() +
" in " + duration + "ms with result: " + result);
return result;
} catch (Exception e) {
Log.e(TAG, "Work failed: " + getClass().getSimpleName(), e);
// Ensure cleanup even on failure
cleanupResources();
endTime = System.currentTimeMillis();
isCompleted = true;
return Result.failure();
}
}
/**
* Initialize resources for the worker
*/
private void initializeResources() {
try {
if (!resourcesInitialized) {
onInitializeResources();
resourcesInitialized = true;
Log.d(TAG, "Resources initialized: " + getClass().getSimpleName());
}
} catch (Exception e) {
Log.e(TAG, "Error initializing resources", e);
throw e;
}
}
/**
* Cleanup resources after work completion
*/
private void cleanupResources() {
try {
if (resourcesInitialized) {
onCleanupResources();
resourcesInitialized = false;
Log.d(TAG, "Resources cleaned up: " + getClass().getSimpleName());
}
} catch (Exception e) {
Log.e(TAG, "Error cleaning up resources", e);
}
}
/**
* Abstract method to perform the actual work
*
* @return Result of the work
*/
@NonNull
protected abstract Result performWork();
/**
* Override to initialize worker-specific resources
*/
protected void onInitializeResources() {
// Default implementation - override in subclasses
}
/**
* Override to cleanup worker-specific resources
*/
protected void onCleanupResources() {
// Default implementation - override in subclasses
}
/**
* Check if work is taking too long and should be cancelled
*
* @param maxDurationMs Maximum duration in milliseconds
* @return true if work should be cancelled
*/
protected boolean shouldCancelWork(long maxDurationMs) {
long currentTime = System.currentTimeMillis();
long elapsed = currentTime - startTime;
if (elapsed > maxDurationMs) {
Log.w(TAG, "Work timeout exceeded: " + elapsed + "ms > " + maxDurationMs + "ms");
return true;
}
return false;
}
/**
* Check if work is cancelled
*
* @return true if work is cancelled
*/
protected boolean isWorkCancelled() {
return isStopped();
}
/**
* Get work duration so far
*
* @return Duration in milliseconds
*/
protected long getWorkDuration() {
if (isCompleted) {
return endTime - startTime;
} else {
return System.currentTimeMillis() - startTime;
}
}
/**
* Log work progress
*
* @param message Progress message
*/
protected void logProgress(String message) {
long duration = getWorkDuration();
Log.d(TAG, "[" + duration + "ms] " + getClass().getSimpleName() + ": " + message);
}
/**
* Create success result with data
*
* @param data Result data
* @return Success result
*/
@NonNull
protected Result createSuccessResult(androidx.work.Data data) {
return Result.success(data);
}
/**
* Create success result
*
* @return Success result
*/
@NonNull
protected Result createSuccessResult() {
return Result.success();
}
/**
* Create failure result with data
*
* @param data Result data
* @return Failure result
*/
@NonNull
protected Result createFailureResult(androidx.work.Data data) {
return Result.failure(data);
}
/**
* Create failure result
*
* @return Failure result
*/
@NonNull
protected Result createFailureResult() {
return Result.failure();
}
/**
* Create retry result with data
*
* @param data Result data
* @return Retry result
*/
@NonNull
protected Result createRetryResult(androidx.work.Data data) {
return Result.retry(data);
}
/**
* Create retry result
*
* @return Retry result
*/
@NonNull
protected Result createRetryResult() {
return Result.retry();
}
/**
* Get worker performance metrics
*
* @return Performance metrics
*/
public WorkerMetrics getMetrics() {
WorkerMetrics metrics = new WorkerMetrics();
metrics.workerName = getClass().getSimpleName();
metrics.startTime = startTime;
metrics.endTime = endTime;
metrics.duration = getWorkDuration();
metrics.isCompleted = isCompleted;
metrics.resourcesInitialized = resourcesInitialized;
return metrics;
}
/**
* Worker performance metrics
*/
public static class WorkerMetrics {
public String workerName;
public long startTime;
public long endTime;
public long duration;
public boolean isCompleted;
public boolean resourcesInitialized;
@Override
public String toString() {
return "WorkerMetrics{" +
"workerName='" + workerName + '\'' +
", duration=" + duration + "ms" +
", isCompleted=" + isCompleted +
", resourcesInitialized=" + resourcesInitialized +
'}';
}
}
}

397
android/plugin/src/main/java/com/timesafari/dailynotification/WorkManagerHygiene.java

@ -0,0 +1,397 @@
/**
* WorkManagerHygiene.java
*
* Optimized WorkManager hygiene and best practices implementation
* Handles worker lifecycle, constraints, retry policies, and resource management
*
* @author Matthew Raymer
* @version 2.0.0 - Optimized Architecture
*/
package com.timesafari.dailynotification;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.BatteryManager;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.work.BackoffPolicy;
import androidx.work.Constraints;
import androidx.work.Data;
import androidx.work.ExistingWorkPolicy;
import androidx.work.NetworkType;
import androidx.work.OneTimeWorkRequest;
import androidx.work.PeriodicWorkRequest;
import androidx.work.WorkInfo;
import androidx.work.WorkManager;
import androidx.work.WorkRequest;
import java.util.concurrent.TimeUnit;
/**
* Optimized WorkManager hygiene and best practices
*
* Responsibilities:
* - Worker lifecycle management
* - Constraint optimization
* - Retry policy management
* - Resource cleanup
* - Performance monitoring
*/
public class WorkManagerHygiene {
private static final String TAG = "WorkManagerHygiene";
// WorkManager instance
private final WorkManager workManager;
private final Context context;
// Worker configuration
private static final String FETCH_WORK_NAME = "daily_notification_fetch";
private static final String MAINTENANCE_WORK_NAME = "daily_notification_maintenance";
private static final String RECOVERY_WORK_NAME = "daily_notification_recovery";
// Timing configuration
private static final long FETCH_INTERVAL_HOURS = 6; // Every 6 hours
private static final long MAINTENANCE_INTERVAL_HOURS = 24; // Daily
private static final long RECOVERY_INTERVAL_HOURS = 12; // Twice daily
// Retry configuration
private static final int MAX_RETRY_ATTEMPTS = 3;
private static final long BACKOFF_DELAY_MINUTES = 15;
/**
* Initialize WorkManager hygiene
*
* @param context Application context
*/
public WorkManagerHygiene(Context context) {
this.context = context;
this.workManager = WorkManager.getInstance(context);
Log.d(TAG, "WorkManagerHygiene initialized");
}
/**
* Schedule optimized fetch worker with proper constraints
*/
public void scheduleFetchWorker() {
try {
Log.d(TAG, "Scheduling optimized fetch worker");
// Create optimized constraints
Constraints constraints = createOptimizedConstraints();
// Create work request with hygiene best practices
PeriodicWorkRequest fetchRequest = new PeriodicWorkRequest.Builder(
DailyNotificationFetchWorker.class,
FETCH_INTERVAL_HOURS,
TimeUnit.HOURS
)
.setConstraints(constraints)
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, BACKOFF_DELAY_MINUTES, TimeUnit.MINUTES)
.addTag("fetch_worker")
.build();
// Enqueue with proper policy
workManager.enqueueUniquePeriodicWork(
FETCH_WORK_NAME,
ExistingWorkPolicy.KEEP,
fetchRequest
);
Log.i(TAG, "Fetch worker scheduled successfully");
} catch (Exception e) {
Log.e(TAG, "Error scheduling fetch worker", e);
}
}
/**
* Schedule optimized maintenance worker
*/
public void scheduleMaintenanceWorker() {
try {
Log.d(TAG, "Scheduling optimized maintenance worker");
// Create constraints for maintenance (less restrictive)
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.NOT_REQUIRED)
.setRequiresBatteryNotLow(true)
.setRequiresStorageNotLow(true)
.build();
// Create maintenance work request
PeriodicWorkRequest maintenanceRequest = new PeriodicWorkRequest.Builder(
DailyNotificationMaintenanceWorker.class,
MAINTENANCE_INTERVAL_HOURS,
TimeUnit.HOURS
)
.setConstraints(constraints)
.setBackoffCriteria(BackoffPolicy.LINEAR, BACKOFF_DELAY_MINUTES, TimeUnit.MINUTES)
.addTag("maintenance_worker")
.build();
// Enqueue maintenance work
workManager.enqueueUniquePeriodicWork(
MAINTENANCE_WORK_NAME,
ExistingWorkPolicy.REPLACE,
maintenanceRequest
);
Log.i(TAG, "Maintenance worker scheduled successfully");
} catch (Exception e) {
Log.e(TAG, "Error scheduling maintenance worker", e);
}
}
/**
* Schedule recovery worker for system recovery
*/
public void scheduleRecoveryWorker() {
try {
Log.d(TAG, "Scheduling recovery worker");
// Create constraints for recovery
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(false) // Allow even on low battery
.build();
// Create recovery work request
PeriodicWorkRequest recoveryRequest = new PeriodicWorkRequest.Builder(
DailyNotificationRecoveryWorker.class,
RECOVERY_INTERVAL_HOURS,
TimeUnit.HOURS
)
.setConstraints(constraints)
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, BACKOFF_DELAY_MINUTES, TimeUnit.MINUTES)
.addTag("recovery_worker")
.build();
// Enqueue recovery work
workManager.enqueueUniquePeriodicWork(
RECOVERY_WORK_NAME,
ExistingWorkPolicy.KEEP,
recoveryRequest
);
Log.i(TAG, "Recovery worker scheduled successfully");
} catch (Exception e) {
Log.e(TAG, "Error scheduling recovery worker", e);
}
}
/**
* Create optimized constraints for different worker types
*/
private Constraints createOptimizedConstraints() {
return new Constraints.Builder()
.setRequiredNetworkType(getOptimalNetworkType())
.setRequiresBatteryNotLow(isBatteryOptimized())
.setRequiresStorageNotLow(true)
.setRequiresDeviceIdle(false) // Don't wait for device idle
.build();
}
/**
* Determine optimal network type based on current conditions
*/
private NetworkType getOptimalNetworkType() {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
if (activeNetwork != null && activeNetwork.isConnected()) {
if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI) {
return NetworkType.UNMETERED; // Prefer WiFi
} else {
return NetworkType.CONNECTED; // Allow mobile data
}
}
return NetworkType.CONNECTED; // Default to any connection
}
/**
* Check if battery optimization is enabled
*/
private boolean isBatteryOptimized() {
BatteryManager batteryManager = (BatteryManager) context.getSystemService(Context.BATTERY_SERVICE);
if (batteryManager != null) {
int batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
return batteryLevel > 20; // Require battery above 20%
}
return true; // Default to true if can't determine
}
/**
* Cancel all workers with proper cleanup
*/
public void cancelAllWorkers() {
try {
Log.d(TAG, "Cancelling all workers");
workManager.cancelUniqueWork(FETCH_WORK_NAME);
workManager.cancelUniqueWork(MAINTENANCE_WORK_NAME);
workManager.cancelUniqueWork(RECOVERY_WORK_NAME);
// Cancel by tags
workManager.cancelAllWorkByTag("fetch_worker");
workManager.cancelAllWorkByTag("maintenance_worker");
workManager.cancelAllWorkByTag("recovery_worker");
Log.i(TAG, "All workers cancelled successfully");
} catch (Exception e) {
Log.e(TAG, "Error cancelling workers", e);
}
}
/**
* Get worker status and health information
*/
public WorkerStatus getWorkerStatus() {
try {
WorkerStatus status = new WorkerStatus();
// Check fetch worker
status.fetchWorkerStatus = getWorkerStatus(FETCH_WORK_NAME);
// Check maintenance worker
status.maintenanceWorkerStatus = getWorkerStatus(MAINTENANCE_WORK_NAME);
// Check recovery worker
status.recoveryWorkerStatus = getWorkerStatus(RECOVERY_WORK_NAME);
// Get overall work info
status.totalWorkCount = workManager.getWorkInfos().get().size();
Log.d(TAG, "Worker status retrieved: " + status.toString());
return status;
} catch (Exception e) {
Log.e(TAG, "Error getting worker status", e);
return new WorkerStatus(); // Return empty status
}
}
/**
* Get status for specific worker
*/
private String getWorkerStatus(String workName) {
try {
var workInfos = workManager.getWorkInfosForUniqueWork(workName).get();
if (workInfos.isEmpty()) {
return "NOT_SCHEDULED";
}
WorkInfo.State state = workInfos.get(0).getState();
return state.toString();
} catch (Exception e) {
Log.e(TAG, "Error getting status for worker: " + workName, e);
return "ERROR";
}
}
/**
* Perform worker hygiene cleanup
*/
public void performHygieneCleanup() {
try {
Log.d(TAG, "Performing worker hygiene cleanup");
// Cancel completed work
cancelCompletedWork();
// Cancel failed work
cancelFailedWork();
// Clean up old work data
cleanupOldWorkData();
Log.i(TAG, "Worker hygiene cleanup completed");
} catch (Exception e) {
Log.e(TAG, "Error performing hygiene cleanup", e);
}
}
/**
* Cancel completed work to free resources
*/
private void cancelCompletedWork() {
try {
var allWorkInfos = workManager.getWorkInfos().get();
for (WorkInfo workInfo : allWorkInfos) {
if (workInfo.getState() == WorkInfo.State.SUCCEEDED) {
workManager.cancelWorkById(workInfo.getId());
Log.d(TAG, "Cancelled completed work: " + workInfo.getId());
}
}
} catch (Exception e) {
Log.e(TAG, "Error cancelling completed work", e);
}
}
/**
* Cancel failed work to prevent retry loops
*/
private void cancelFailedWork() {
try {
var allWorkInfos = workManager.getWorkInfos().get();
for (WorkInfo workInfo : allWorkInfos) {
if (workInfo.getState() == WorkInfo.State.FAILED) {
workManager.cancelWorkById(workInfo.getId());
Log.d(TAG, "Cancelled failed work: " + workInfo.getId());
}
}
} catch (Exception e) {
Log.e(TAG, "Error cancelling failed work", e);
}
}
/**
* Clean up old work data
*/
private void cleanupOldWorkData() {
try {
// This would clean up old work data from storage
// Implementation depends on specific storage mechanism
Log.d(TAG, "Cleaned up old work data");
} catch (Exception e) {
Log.e(TAG, "Error cleaning up old work data", e);
}
}
/**
* Worker status container
*/
public static class WorkerStatus {
public String fetchWorkerStatus = "UNKNOWN";
public String maintenanceWorkerStatus = "UNKNOWN";
public String recoveryWorkerStatus = "UNKNOWN";
public int totalWorkCount = 0;
@Override
public String toString() {
return "WorkerStatus{" +
"fetchWorkerStatus='" + fetchWorkerStatus + '\'' +
", maintenanceWorkerStatus='" + maintenanceWorkerStatus + '\'' +
", recoveryWorkerStatus='" + recoveryWorkerStatus + '\'' +
", totalWorkCount=" + totalWorkCount +
'}';
}
}
}
Loading…
Cancel
Save