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

如何在OnResponse外获取Retrofit响应并返回给官方推荐架构的Repository层

根本原因

你遇到的问题本质是异步调用和同步返回的时序冲突:Retrofit的enqueue方法是异步执行的,发起请求后会立刻执行后续代码,而onResponse回调要等到网络请求结束才会触发,你在回调执行前就返回了还没赋值的user,自然拿到的是空值。你想让异步方法直接同步返回对象的思路是不可行的,有三种成熟的解决方案。


方案1:全链路回调改造(Java适用)

从DataSource到Repository再到上层都采用回调传递结果,不要尝试让login方法同步返回Result。

public class LoginDataSource {
    public static Retrofit retrofit = null;

    // 去掉返回值,增加回调参数
    public void login(String username, String password, final GetUserResponse callback) {
        try {
            retrofit = new Retrofit.Builder()
                    .baseUrl("https://myserver")
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
            PostEndPoint endPoint = retrofit.create(PostEndPoint.class);
            Call<LoggedInUser> call = endPoint.getUser("login", username, password);

            call.enqueue(new Callback<LoggedInUser>() {
                @Override
                public void onResponse(Call<LoggedInUser> call, Response<LoggedInUser> response) {
                    if (response.isSuccessful()){
                        // 直接把结果通过回调向上传
                        callback.onSuccess(new Result.Success<>(response.body()));
                    } else {
                        callback.onError(new Result.Error(new Exception("请求失败,错误码:" + response.code())));
                    }
                }

                @Override
                public void onFailure(Call<LoggedInUser> call, Throwable t) {
                    callback.onError(new Result.Error(t));
                }
            });
        } catch (Exception e) {
            callback.onError(new Result.Error(e));
        }
    }

    // 回调接口改成支持成功/失败两种状态
    public interface GetUserResponse {
        void onSuccess(Result<LoggedInUser> result);
        void onError(Result.Error error);
    }
}

Repository层对应改造即可,上层调用时直接在回调里处理结果:

public class LoginRepository {
    private LoginDataSource dataSource = new LoginDataSource();

    public void login(String username, String password, LoginDataSource.GetUserResponse callback) {
        dataSource.login(username, password, callback);
    }
}

方案2:RxJava适配(Java/Kotlin适用)

如果不想写多层嵌套回调,可以给Retrofit增加RxJava适配器,把请求转为Observable/Flowable,通过链式调用传递结果:

// 新增RxJava适配器依赖
// implementation 'com.squareup.retrofit2:adapter-rxjava3:版本号'
public class LoginDataSource {
    public static Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("https://myserver")
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
            .build();
    PostEndPoint endPoint = retrofit.create(PostEndPoint.class);

    public Observable<Result<LoggedInUser>> login(String username, String password) {
        return endPoint.getUser("login", username, password)
                .map(user -> (Result<LoggedInUser>) new Result.Success<>(user))
                .onErrorReturn(e -> new Result.Error(e))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }
}

// PostEndPoint接口对应修改返回值
interface PostEndPoint {
    @GET("你的接口路径")
    Observable<LoggedInUser> getUser(@Query("type") String type, @Query("username") String username, @Query("password") String password);
}

方案3:协程改造(Kotlin官方首选方案)

Kotlin环境下可以直接用Retrofit的suspend函数支持,把异步请求转成挂起函数,用同步写法拿到结果,完全避免回调嵌套:

// PostEndPoint接口增加suspend关键字
interface PostEndPoint {
    @GET("你的接口路径")
    suspend fun getUser(@Query("type") type: String, @Query("username") username: String, @Query("password") password: String): LoggedInUser
}

class LoginDataSource {
    private val retrofit = Retrofit.Builder()
        .baseUrl("https://myserver")
        .addConverterFactory(GsonConverterFactory.create())
        .build()
    private val endPoint = retrofit.create(PostEndPoint::class.java)

    // 直接返回Result,不需要回调
    suspend fun login(username: String, password: String): Result<LoggedInUser> {
        return try {
            val user = endPoint.getUser("login", username, password)
            Result.Success(user)
        } catch (e: Exception) {
            Result.Error(e)
        }
    }
}

Repository和ViewModel层直接在协程作用域里调用login方法即可拿到结果。


注意:绝对不要在主线程直接调用call.execute()执行同步请求,会阻塞主线程触发ANR异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.20 11:54:04