Android高级重试策略:协程+指数退避的最佳实践

以下是几种优化后的实现方式,增加了更好的错误处理、取消机制和可配置性。
优化方案一:Kotlin 协程 + 指数退避 (推荐)

class RetryTaskExecutor(
    private val maxRetries: Int = 3,
    private val initialDelay: Long = 1000L,
    private val maxDelay: Long = 10000L,
    private val factor: Double = 2.0,
    private val coroutineScope: CoroutineScope = CoroutineScope(Dispatchers.Main)
) {
    private var currentJob: Job? = null
    
    fun execute(
        task: suspend () -> Boolean,
        onSuccess: () -> Unit,
        onFailure: (Throwable?) -> Unit,
        onRetry: (attempt: Int, nextDelay: Long) -> Unit = { _, _ -> }
    ) {
        cancel() // 取消之前的任务
        
        currentJob = coroutineScope.launch {
            var currentDelay = initialDelay
            var attempt = 0
            
            while (attempt <= maxRetries) {
                attempt++
                try {
                    val result = withContext(Dispatchers.IO) { task() }
                    if (result) {
                        onSuccess()
                        return@launch
                    }
                } catch (e: Exception) {
                    if (attempt > maxRetries) {
                        onFailure(e)
                        return@launch
                    }
                }
                
                if (attempt <= maxRetries) {
                    onRetry(attempt, currentDelay)
                    delay(currentDelay)
                    currentDelay = (currentDelay * factor).toLong().coerceAtMost(maxDelay)
                } else {
                    onFailure(null)
                }
            }
        }
    }
    
    fun cancel() {
        currentJob?.cancel()
        currentJob = null
    }
}

// 使用示例
val retryExecutor = RetryTaskExecutor(maxRetries = 3)

fun startTask() {
    retryExecutor.execute(
        task = {
            // 执行你的任务,返回 true 表示成功
            doSomeWork()
        },
        onSuccess = {
            showSuccessMessage()
        },
        onFailure = { error ->
            showErrorMessage(error)
        },
        onRetry = { attempt, nextDelay ->
            logRetryAttempt(attempt, nextDelay)
        }
    )
}

fun cancelTask() {
    retryExecutor.cancel()
}

优化方案二:Java 线程池 + 回调

public class RetryTaskExecutor {
    private final int maxRetries;
    private final long initialDelay;
    private final long maxDelay;
    private final double factor;
    private final ScheduledExecutorService executor;
    
    private Future<?> currentFuture;
    
    public RetryTaskExecutor(int maxRetries, long initialDelay, long maxDelay, double factor) {
        this.maxRetries = maxRetries;
        this.initialDelay = initialDelay;
        this.maxDelay = maxDelay;
        this.factor = factor;
        this.executor = Executors.newSingleThreadScheduledExecutor();
    }
    
    public void execute(
        Callable<Boolean> task,
        Runnable onSuccess,
        Consumer<Throwable> onFailure,
        BiConsumer<Integer, Long> onRetry
    ) {
        cancel();
        
        AtomicInteger attempt = new AtomicInteger(0);
        AtomicLong currentDelay = new AtomicLong(initialDelay);
        
        currentFuture = executor.schedule(new Runnable() {
            @Override
            public void run() {
                int currentAttempt = attempt.incrementAndGet();
                try {
                    boolean result = task.call();
                    if (result) {
                        runOnUiThread(onSuccess);
                        return;
                    }
                } catch (Exception e) {
                    if (currentAttempt > maxRetries) {
                        runOnUiThread(() -> onFailure.accept(e));
                        return;
                    }
                }
                
                if (currentAttempt <= maxRetries) {
                    long nextDelay = (long) (currentDelay.get() * factor);
                    nextDelay = Math.min(nextDelay, maxDelay);
                    currentDelay.set(nextDelay);
                    
                    runOnUiThread(() -> onRetry.accept(currentAttempt, nextDelay));
                    currentFuture = executor.schedule(this, nextDelay, TimeUnit.MILLISECONDS);
                } else {
                    runOnUiThread(() -> onFailure.accept(null));
                }
            }
        }, 0, TimeUnit.MILLISECONDS);
    }
    
    public void cancel() {
        if (currentFuture != null) {
            currentFuture.cancel(true);
            currentFuture = null;
        }
    }
    
    private void runOnUiThread(Runnable action) {
        new Handler(Looper.getMainLooper()).post(action);
    }
    
    public void shutdown() {
        executor.shutdownNow();
    }
}

// 使用示例
RetryTaskExecutor executor = new RetryTaskExecutor(3, 1000, 10000, 2.0);

void startTask() {
    executor.execute(
        () -> {
            // 执行任务
            return doSomeWork();
        },
        this::onSuccess,
        error -> onFailure(error),
        (attempt, delay) -> onRetry(attempt, delay)
    );
}

void cancelTask() {
    executor.cancel();
}

优化方案三:RxJava 实现 (适合已有 RxJava 的项目)

public class RxRetryExecutor {
    private final int maxRetries;
    private final long initialDelay;
    private final long maxDelay;
    private final double factor;
    
    private Disposable disposable;
    
    public RxRetryExecutor(int maxRetries, long initialDelay, long maxDelay, double factor) {
        this.maxRetries = maxRetries;
        this.initialDelay = initialDelay;
        this.maxDelay = maxDelay;
        this.factor = factor;
    }
    
    public void execute(
        Callable<Boolean> task,
        Action onSuccess,
        Consumer<Throwable> onFailure,
        BiConsumer<Integer, Long> onRetry
    ) {
        dispose();
        
        disposable = Observable.fromCallable(task)
            .subscribeOn(Schedulers.io())
            .retryWhen(errors -> errors
                .zipWith(Observable.range(1, maxRetries + 1), (error, attempt) -> {
                    if (attempt > maxRetries) {
                        throw Exceptions.propagate(error);
                    }
                    
                    long delay = calculateDelay(attempt);
                    onRetry.accept(attempt, delay);
                    return Observable.timer(delay, TimeUnit.MILLISECONDS);
                })
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                success -> {
                    if (success) {
                        onSuccess.run();
                    } else {
                        onFailure.accept(null);
                    }
                },
                onFailure
            );
    }
    
    private long calculateDelay(int attempt) {
        long delay = (long) (initialDelay * Math.pow(factor, attempt - 1));
        return Math.min(delay, maxDelay);
    }
    
    public void dispose() {
        if (disposable != null && !disposable.isDisposed()) {
            disposable.dispose();
        }
    }
}

// 使用示例
RxRetryExecutor executor = new RxRetryExecutor(3, 1000, 10000, 2.0);

void startTask() {
    executor.execute(
        () -> doSomeWork(),
        this::onSuccess,
        error -> onFailure(error),
        (attempt, delay) -> onRetry(attempt, delay)
    );
}

void cancelTask() {
    executor.dispose();
}

优化点说明
指数退避策略:每次重试间隔时间按指数增长,避免频繁重试给服务器造成压力

可配置参数:最大重试次数、初始延迟、最大延迟、增长因子都可配置

完善的取消机制:可以随时取消正在进行的重试任务

状态回调:提供成功、失败和每次重试前的回调

线程安全:正确处理了线程切换,UI 更新在主线程执行

资源释放:提供了适当的资源释放方法

异常处理:区分业务失败和系统异常

选择哪种方案取决于你的项目:

新项目推荐使用 Kotlin 协程方案

已有 RxJava 的项目可以使用 RxJava 方案

纯 Java 项目可以使用线程池方案

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值