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

如何等待Retrofit的enqueue执行完成且不阻塞UI线程?

问题:异步请求完成后再切换Fragment且不阻塞UI线程

我通过以下代码在按钮的onClick()方法中发起异步注册请求:

AuthAPI authAPI = retrofitService.getRetrofit().create(AuthAPI.class);

authAPI.registerUser(requestBody)
    .enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(@NonNull Call<ResponseBody> call,
            @NonNull Response<ResponseBody> response) {
            // 响应处理
        }

        @Override
        public void onFailure(@NonNull Call<ResponseBody> call,
            @NonNull Throwable t) {
            // 失败处理
        }
    });

现在需要在请求完成后替换当前Fragment,但直接在onClick()里切换会因为异步请求未完成导致崩溃。用execute()会阻塞UI线程,让ProgressBar动画卡住,不符合需求。想知道怎么在等待响应的同时不阻塞UI,保证ProgressBar正常运行。


解决方案1:在回调内执行Fragment切换(最直接方案)

核心逻辑就是把Fragment切换代码放到onResponse和onFailure回调里——这两个方法本身就在UI线程执行,既不会阻塞UI,又能确保请求完成后再执行切换:

button.setOnClickListener(v -> {
    // 点击后先显示ProgressBar
    progressBar.setVisibility(View.VISIBLE);
    
    AuthAPI authAPI = retrofitService.getRetrofit().create(AuthAPI.class);
    authAPI.registerUser(requestBody)
        .enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(@NonNull Call<ResponseBody> call,
                @NonNull Response<ResponseBody> response) {
                progressBar.setVisibility(View.GONE);
                // 先处理业务逻辑,比如校验返回结果
                if (response.isSuccessful()) {
                    // 请求完成后切换Fragment
                    getParentFragmentManager().beginTransaction()
                        .replace(R.id.container, new TargetFragment())
                        .addToBackStack(null)
                        .commit();
                } else {
                    // 处理请求成功但业务失败的情况(比如注册重复提示)
                }
            }

            @Override
            public void onFailure(@NonNull Call<ResponseBody> call,
                @NonNull Throwable t) {
                progressBar.setVisibility(View.GONE);
                // 处理请求失败(比如弹窗提示网络错误)
            }
        });
});

解决方案2:使用Kotlin协程(推荐,代码更简洁)

如果项目用Kotlin,配合Retrofit的挂起函数可以实现更简洁的异步处理,且自动管理线程切换:

  1. 先把接口改成挂起函数:
interface AuthAPI {
    @POST("register")
    suspend fun registerUser(@Body requestBody: RequestBody): Response<ResponseBody>
}
  1. 在Fragment的生命周期协程里执行请求:
button.setOnClickListener {
    lifecycleScope.launch {
        progressBar.visibility = View.VISIBLE
        try {
            val response = authAPI.registerUser(requestBody)
            if (response.isSuccessful) {
                // 请求完成后切换Fragment
                parentFragmentManager.beginTransaction()
                    .replace(R.id.container, TargetFragment())
                    .addToBackStack(null)
                    .commit()
            }
        } catch (e: Exception) {
            // 处理请求失败逻辑
        } finally {
            progressBar.visibility = View.GONE
        }
    }
}

lifecycleScope会绑定Fragment生命周期,避免内存泄漏;挂起函数registerUser在后台执行请求,不会阻塞UI,ProgressBar动画正常运行。

解决方案3:LiveData + ViewModel(MVVM架构方案)

如果遵循MVVM架构,可以把请求逻辑放到ViewModel中,用LiveData通知Fragment处理结果:

  1. 编写ViewModel类:
public class AuthViewModel extends ViewModel {
    private final MutableLiveData<Boolean> registerResult = new MutableLiveData<>();
    private final MutableLiveData<Throwable> error = new MutableLiveData<>();
    private final AuthAPI authAPI;

    public AuthViewModel() {
        authAPI = retrofitService.getRetrofit().create(AuthAPI.class);
    }

    public void registerUser(RequestBody requestBody) {
        authAPI.registerUser(requestBody)
            .enqueue(new Callback<ResponseBody>() {
                @Override
                public void onResponse(@NonNull Call<ResponseBody> call, @NonNull Response<ResponseBody> response) {
                    registerResult.postValue(response.isSuccessful());
                }

                @Override
                public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable t) {
                    error.postValue(t);
                }
            });
    }

    public LiveData<Boolean> getRegisterResult() {
        return registerResult;
    }

    public LiveData<Throwable> getError() {
        return error;
    }
}
  1. 在Fragment中观察LiveData:
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    AuthViewModel authViewModel = new ViewModelProvider(this).get(AuthViewModel.class);
    
    button.setOnClickListener(v -> {
        progressBar.setVisibility(View.VISIBLE);
        authViewModel.registerUser(requestBody);
    });

    // 观察注册结果
    authViewModel.getRegisterResult().observe(getViewLifecycleOwner(), isSuccess -> {
        progressBar.setVisibility(View.GONE);
        if (isSuccess) {
            getParentFragmentManager().beginTransaction()
                .replace(R.id.container, new TargetFragment())
                .addToBackStack(null)
                .commit();
        }
    });

    // 观察错误信息
    authViewModel.getError().observe(getViewLifecycleOwner(), throwable -> {
        progressBar.setVisibility(View.GONE);
        // 处理错误提示
    });
}

这种方式将业务逻辑与UI分离,更利于代码维护,同时也不会阻塞UI线程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 01:52:18