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

点击返回按钮后执行多HTTP请求,待成功响应后再执行返回操作的实现方法

实现方案:多请求完成后再返回页面

要实现点击BackButton时先发起多个异步HTTP请求,等待全部成功后再返回页面,我们可以按View-Presenter分层协作的思路来实现,核心是在Presenter中管理多请求的状态,待所有请求成功后通知View执行返回操作。

核心思路

  1. View层触发事件:点击BackButton时,不直接返回,而是调用Presenter的处理方法。
  2. Presenter管理多请求:并行发起所有HTTP请求,跟踪每个请求的成功状态;当所有请求都成功时,通知View返回。
  3. View执行返回:接收Presenter的通知后,执行页面返回(如finish()或Navigation组件的回退)。

方案一:使用RxJava(推荐,适合已有RxJava的项目)

RxJava的zip操作符可以完美合并多个Observable,等待所有请求完成后统一处理结果。

1. 定义契约接口(DetailsScreenContract.java)

先定义View和Presenter的交互契约,确保分层清晰:

public interface DetailsScreenContract {
    interface View {
        void navigateBack(); // 执行页面返回
        void showRequestError(String errorMsg); // 请求失败时提示用户
    }

    interface Presenter {
        void onBackButtonClicked(); // 处理BackButton点击事件
        void attachView(View view); // 绑定View
        void detachView(); // 解绑View,防止内存泄漏
    }
}

2. Presenter实现(DetailsScreenPresenter.java)

在Presenter中发起多请求,用zip合并结果:

public class DetailsScreenPresenter implements DetailsScreenContract.Presenter {
    private DetailsScreenContract.View mView;
    private CompositeDisposable mDisposable = new CompositeDisposable();
    private ApiService mApiService; // 假设这是你的API请求服务类

    public DetailsScreenPresenter(ApiService apiService) {
        mApiService = apiService;
    }

    @Override
    public void attachView(DetailsScreenContract.View view) {
        mView = view;
    }

    @Override
    public void detachView() {
        mView = null;
        mDisposable.dispose(); // 取消所有未完成的请求,避免内存泄漏
    }

    @Override
    public void onBackButtonClicked() {
        // 1. 定义多个请求Observable
        Observable<ResponseBody> request1 = mApiService.makeFirstRequest()
                .subscribeOn(Schedulers.io());
        Observable<ResponseBody> request2 = mApiService.makeSecondRequest()
                .subscribeOn(Schedulers.io());
        Observable<ResponseBody> request3 = mApiService.makeThirdRequest()
                .subscribeOn(Schedulers.io());

        // 2. 使用zip合并所有请求,等待全部成功
        Disposable disposable = Observable.zip(request1, request2, request3,
                (resp1, resp2, resp3) -> {
                    // 验证每个请求是否成功
                    if (!resp1.contentType().toString().contains("success") 
                        || !resp2.contentType().toString().contains("success")
                        || !resp3.contentType().toString().contains("success")) {
                        throw new RuntimeException("部分请求失败");
                    }
                    return true;
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                        success -> {
                            if (mView != null) {
                                mView.navigateBack(); // 所有请求成功,通知返回
                            }
                        },
                        error -> {
                            if (mView != null) {
                                mView.showRequestError("请求失败:" + error.getMessage());
                            }
                        }
                );

        mDisposable.add(disposable);
    }
}

3. View层实现(DetailsScreen.java)

在Activity中绑定Presenter,处理BackButton点击:

public class DetailsScreen extends AppCompatActivity implements DetailsScreenContract.View {
    private DetailsScreenContract.Presenter mPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_details);

        // 初始化Presenter
        mPresenter = new DetailsScreenPresenter(new ApiService());
        mPresenter.attachView(this);

        // 设置BackButton点击事件
        findViewById(R.id.btn_back).setOnClickListener(v -> {
            mPresenter.onBackButtonClicked(); // 调用Presenter处理,而非直接返回
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mPresenter.detachView(); // 解绑Presenter,避免内存泄漏
    }

    @Override
    public void navigateBack() {
        // 执行页面返回,根据你的导航方式选择:
        finish(); // 传统Activity返回
        // 或用Navigation组件:NavHostFragment.findNavController(this).popBackStack();
    }

    @Override
    public void showRequestError(String errorMsg) {
        Toast.makeText(this, errorMsg, Toast.LENGTH_SHORT).show();
    }
}

方案二:原生实现(不用RxJava,用CountDownLatch+OkHttp)

如果项目未使用RxJava,可以用CountDownLatch跟踪请求完成状态,结合OkHttp的异步回调实现。

Presenter实现(DetailsScreenPresenter.java)

public class DetailsScreenPresenter implements DetailsScreenContract.Presenter {
    private DetailsScreenContract.View mView;
    private ApiService mApiService;
    private int mTotalRequests = 3; // 请求总数
    private int mSuccessCount = 0;
    private boolean mIsRequesting = false; // 防止重复点击

    public DetailsScreenPresenter(ApiService apiService) {
        mApiService = apiService;
    }

    @Override
    public void attachView(DetailsScreenContract.View view) {
        mView = view;
    }

    @Override
    public void detachView() {
        mView = null;
    }

    @Override
    public void onBackButtonClicked() {
        if (mIsRequesting) return;
        mIsRequesting = true;
        mSuccessCount = 0;

        // 发起第一个请求
        mApiService.makeFirstRequest(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                if (response.isSuccessful()) {
                    onSingleRequestSuccess();
                } else {
                    onSingleRequestFailed("第一个请求失败");
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                onSingleRequestFailed(t.getMessage());
            }
        });

        // 发起第二个请求
        mApiService.makeSecondRequest(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                if (response.isSuccessful()) {
                    onSingleRequestSuccess();
                } else {
                    onSingleRequestFailed("第二个请求失败");
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                onSingleRequestFailed(t.getMessage());
            }
        });

        // 发起第三个请求
        mApiService.makeThirdRequest(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                if (response.isSuccessful()) {
                    onSingleRequestSuccess();
                } else {
                    onSingleRequestFailed("第三个请求失败");
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                onSingleRequestFailed(t.getMessage());
            }
        });
    }

    private void onSingleRequestSuccess() {
        mSuccessCount++;
        if (mSuccessCount == mTotalRequests) {
            // 切换到主线程通知View返回
            new Handler(Looper.getMainLooper()).post(() -> {
                if (mView != null) {
                    mView.navigateBack();
                }
                mIsRequesting = false;
            });
        }
    }

    private void onSingleRequestFailed(String errorMsg) {
        // 切换到主线程提示错误
        new Handler(Looper.getMainLooper()).post(() -> {
            if (mView != null) {
                mView.showRequestError(errorMsg);
            }
            mIsRequesting = false;
        });
    }
}

View层代码

和方案一的View层代码一致,点击BackButton调用mPresenter.onBackButtonClicked()即可。


关键注意事项

  1. 防止重复点击:用mIsRequesting标记避免用户多次点击发起重复请求。
  2. 内存泄漏:Presenter在detachView时要取消所有未完成的请求(RxJava用CompositeDisposable.dispose(),OkHttp可以保存所有Call对象并在detachView时调用call.cancel())。
  3. 线程切换:所有UI操作(包括通知View返回、显示Toast)必须在主线程执行,所以异步回调后要切换到主线程。
  4. 错误处理:如果某个请求失败,要及时通知用户,并且终止返回流程,避免部分请求未完成就返回。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 03:37:34