You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Google Play Integrity退避重试阻塞主线程的解决方案咨询

Google Play Integrity 重试逻辑阻塞主线程的解决方法

问题描述

当前实现Google Play Integrity获取token的代码如下:

// Create an instance of a manager.
IntegrityManager integrityManager =
    IntegrityManagerFactory.create(getApplicationContext());

// Request the integrity token by providing a nonce.
Task<IntegrityTokenResponse> integrityTokenResponse =
    integrityManager
        .requestIntegrityToken(
            IntegrityTokenRequest.builder().setNonce(nonce).build());

integrityTokenResponse.addOnSuccessListener(this::handleSuccess);
integrityTokenResponse.addOnFailureListener(this::handleFailure);

在handleFailure监听器中使用Thread.sleep(retryMillis)实现指数退避重试,但该逻辑运行在主线程,导致UI阻塞。需要实现不阻塞主线程的重试方案,或者将Play Integrity的执行移至其他线程。


解决方案一:用Handler实现非阻塞的指数退避重试

直接在失败回调中借助Handler.postDelayed延迟发起重试,完全避免主线程阻塞:

private int retryCount = 0;
private static final int MAX_RETRIES = 3;
private static final long INITIAL_RETRY_DELAY = 1000; // 初始延迟1秒

private void handleFailure(Exception e) {
    if (retryCount < MAX_RETRIES) {
        // 计算指数退避延迟
        long retryMillis = (long) (INITIAL_RETRY_DELAY * Math.pow(2, retryCount));
        new Handler(Looper.getMainLooper()).postDelayed(() -> {
            retryCount++;
            reRequestIntegrityToken();
        }, retryMillis);
    } else {
        // 重试次数耗尽,处理最终失败(如提示用户、记录日志)
    }
}

// 封装重复请求逻辑
private void reRequestIntegrityToken() {
    IntegrityManager integrityManager = IntegrityManagerFactory.create(getApplicationContext());
    Task<IntegrityTokenResponse> integrityTokenResponse =
        integrityManager.requestIntegrityToken(
            IntegrityTokenRequest.builder().setNonce(nonce).build());

    integrityTokenResponse.addOnSuccessListener(this::handleSuccess);
    integrityTokenResponse.addOnFailureListener(this::handleFailure);
}

解决方案二:将请求移至后台线程执行

把整个请求+重试逻辑放到后台线程执行,即使使用Thread.sleep也不会阻塞UI。推荐用Coroutine(适配现代Android),也可以用AsyncTask兼容旧版本:

方案2.1:用Coroutine实现(推荐)

确保项目已引入Coroutine依赖,可在ViewModel或Repository中实现:

// 示例在ViewModel中,使用viewModelScope管理生命周期,避免内存泄漏
private val MAX_RETRIES = 3
private val INITIAL_RETRY_DELAY = 1000L

fun requestIntegrityTokenWithRetry(nonce: String) {
    viewModelScope.launch(Dispatchers.IO) {
        var retryCount = 0
        var requestSuccess = false
        
        while (retryCount < MAX_RETRIES && !requestSuccess) {
            try {
                val integrityManager = IntegrityManagerFactory.create(getApplicationContext())
                val response = integrityManager.requestIntegrityToken(
                    IntegrityTokenRequest.builder().setNonce(nonce).build()
                ).await() // 挂起函数,不阻塞线程
                
                // 切换回主线程处理成功结果
                withContext(Dispatchers.Main) {
                    handleSuccess(response)
                }
                requestSuccess = true
            } catch (e: Exception) {
                retryCount++
                if (retryCount < MAX_RETRIES) {
                    val delayMillis = (INITIAL_RETRY_DELAY * Math.pow(2.0, retryCount - 1.0)).toLong()
                    delay(delayMillis) // Coroutine自带的非阻塞延迟
                } else {
                    // 切换回主线程处理最终失败
                    withContext(Dispatchers.Main) {
                        handleFailure(e)
                    }
                }
            }
        }
    }
}

方案2.2:用AsyncTask实现(兼容Android 11及以下)

private class IntegrityTokenTask extends AsyncTask<Void, Void, IntegrityTokenResponse> {
    private int retryCount = 0;
    private Exception requestError;
    private static final int MAX_RETRIES = 3;
    private static final long INITIAL_RETRY_DELAY = 1000L;

    @Override
    protected IntegrityTokenResponse doInBackground(Void... voids) {
        while (retryCount < MAX_RETRIES) {
            try {
                IntegrityManager integrityManager = IntegrityManagerFactory.create(getApplicationContext());
                // 用Tasks.await将异步Task转为同步调用,运行在后台线程
                return Tasks.await(integrityManager.requestIntegrityToken(
                    IntegrityTokenRequest.builder().setNonce(nonce).build()
                ));
            } catch (Exception e) {
                retryCount++;
                requestError = e;
                if (retryCount < MAX_RETRIES) {
                    long delayMillis = (long) (INITIAL_RETRY_DELAY * Math.pow(2, retryCount - 1));
                    try {
                        Thread.sleep(delayMillis); // 后台线程sleep,不影响UI
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        return null;
                    }
                }
            }
        }
        return null;
    }

    @Override
    protected void onPostExecute(IntegrityTokenResponse response) {
        if (response != null) {
            handleSuccess(response);
        } else {
            handleFailure(requestError);
        }
    }
}

// 启动任务
new IntegrityTokenTask().execute();

关键注意点

  • 必须限制最大重试次数,避免无限重试消耗资源
  • 指数退避的延迟时间要合理,避免给服务器造成过大压力
  • 用Coroutine时,优先使用与生命周期绑定的Scope(如viewModelScope),防止内存泄漏

内容的提问来源于stack exchange,提问作者Manjusha Vuyyuru

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 01:15:46