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
相关产品推荐
相关产品推荐

