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

Android登录页调用Retrofit异步任务未等待完成的问题问询

解决AsyncTask执行时主线程不等待的问题

问题分析

你的核心问题在于AsyncTask的execute()方法是异步非阻塞的——调用它之后,主线程会立刻继续执行后续代码,不会等待doInBackground里的API请求完成。所以你在checkIfAuthenticated里,刚启动runAuthenticationCheck就去读取SharedPreferences并判断跳转,这时候API请求可能还没结束,token的清理操作(如果失效的话)还没执行,导致逻辑完全不符合预期。

你的解决方案:使用.get()阻塞主线程

你提到的给execute()加上.get()的方法是可行的,它会强制当前线程(这里是主线程)等待AsyncTask完成所有流程(包括doInBackground和onPostExecute)之后再继续执行。修改后的代码如下:

public void runAuthenticationCheck (String mobile_token, String Access_token) {
    checkAuthTask = new checkAuthenticationTask(mobile_token, Access_token);
    try {
        checkAuthTask.execute((Void) null).get();
    } catch (ExecutionException e) {
        e.printStackTrace();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

重要提醒

不过要特别注意:.get()会阻塞主线程,如果你的API请求耗时较长(比如网络环境差的时候),很容易触发ANR(应用无响应)错误。所以建议在调用这个方法前,给用户显示一个加载提示(比如ProgressDialog或者自定义的加载弹窗),让用户知道APP正在处理中,避免误以为APP卡死。

更优的异步方案:使用回调接口(推荐)

如果不想阻塞主线程,更优雅且符合Android开发规范的方式是给AuthenticationGlobal添加回调接口,在AsyncTask的onPostExecute里通知LoginActivity执行后续逻辑。这样既不会阻塞主线程,又能严格保证逻辑执行顺序。

具体实现步骤如下:

  1. 定义一个回调接口:
public interface AuthCheckCallback {
    void onAuthCheckComplete(boolean isAuthenticated);
}
  1. 修改runAuthenticationCheck方法,接收回调参数:
public void runAuthenticationCheck (String mobile_token, String Access_token, AuthCheckCallback callback) {
    checkAuthTask = new checkAuthenticationTask(mobile_token, Access_token, callback);
    checkAuthTask.execute((Void) null);
}
  1. 修改checkAuthenticationTask,持有回调并在onPostExecute触发:
public class checkAuthenticationTask extends AsyncTask<Void, Void, Boolean> {
    private GetDataService service;
    private String mobile_token;
    private String access_token;
    private AuthCheckCallback callback; // 新增回调引用

    checkAuthenticationTask(String Access_token, String Mobile_token, AuthCheckCallback callback) {
        mobile_token = Mobile_token;
        access_token = Access_token;
        this.callback = callback;
        service = RetrofitClientInstance.getRetrofitInstance().create(GetDataService.class);
    }

    @Override
    protected Boolean doInBackground(Void... params) {
        boolean isAuthenticated = true;
        try {
            Call<CheckAuthenticationResponse> call = service.checkAuthentication(access_token,mobile_token);
            Response<CheckAuthenticationResponse> response = call.execute();
            if (response.code() != 200){
                clearAuthentication();
                Log.e("AuthKey Global","Expired0");
                isAuthenticated = false;
            }
        } catch (IOException ea) {
            clearAuthentication();
            Log.e("AuthKey Global","Expired1");
            Log.e("AuthenticationResponseError Global","Network Went Wrong");
            ea.printStackTrace();
            isAuthenticated = false;
        }
        return isAuthenticated;
    }

    @Override
    protected void onPostExecute(final Boolean isAuthenticated) {
        // 触发回调,通知LoginActivity结果
        if (callback != null) {
            callback.onAuthCheckComplete(isAuthenticated);
        }
        
        if (isAuthenticated) {
            Log.e("AuthKey Global","Done");
        } else {
            clearAuthentication();
            Log.e("AuthKey Global","Expired2");
        }
    }

    // 其他原有方法保持不变
}
  1. 在LoginActivity的checkIfAuthenticated里使用回调:
private void checkIfAuthenticated(){
    SharedPreferences reader_auth = getSharedPreferences(getString(R.string.auth_preferences), MODE_PRIVATE);
    String auth_key = reader_auth.getString(getString(R.string.auth_access_key),null);
    String mobile_token = reader_auth.getString(getString(R.string.auth_mobile_token),null);
    
    if (auth_key != null) {
        authGlobal = new AuthenticationGlobal(this);
        authGlobal.runAuthenticationCheck(auth_key,mobile_token, new AuthCheckCallback() {
            @Override
            public void onAuthCheckComplete(boolean isAuthenticated) {
                if (isAuthenticated) {
                    Log.d("Auth Key Check 1", auth_key);
                    MoveToDashboardActivity();
                } else {
                    // token失效,留在登录页或者提示用户重新登录
                    Log.d("Auth Key Check", "Token expired or invalid");
                }
            }
        });
    }
}

这种方式既保持了异步执行的优势(不阻塞主线程,避免ANR),又能严格控制逻辑顺序,是Android处理异步任务的标准实践。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:07:59