以下是几种优化后的实现方式,增加了更好的错误处理、取消机制和可配置性。
优化方案一: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 项目可以使用线程池方案