onChanged() 在 HttpLoggingInterceptor 记录网络响应之前触发

onChanged() is triggered before the network response is logged by the HttpLoggingInterceptor

我正在尝试掌握 Android 中的 MVVM 架构,并且正在为此开发一个示例应用程序。我暂时避免使用 Repository class,它避免了关注点分离,但我想先更好地理解 ViewModel 和 LiveData。我有一个片段,我在其中使用改造和 viewmodel 实例进行网络调用。然后使用相同的 viewmodel 对象进行相同的调用,但参数值不同。现在 onChanged 被触发,当我记录响应时(使用 log.d),我在其中得到了旧的响应。在几毫秒的延迟之后,HttpLoggingInterceptor 记录新的响应。我已经尝试了很多东西,但我无法弄清楚发生了什么。在搜索这个问题时,我发现了这个:,但我不明白如何实现给定的答案。

代码:
Api接口

public interface ApiInterface {
@GET("fetch")
Call<String> fetchData(@Query("param1") String param1,
                       @Query("param2") String param2,
                       @Query("param3") String param3,
                       @Query("param4") String param4,
                       @Query("param5") String param5);

ViewModelData

public class ViewModelData extends ViewModel {
private MutableLiveData<String> data = new MutableLiveData<>();

private final String TAG = getClass().getSimpleName();

public LiveData<String> getData(String param1, String param2, String param3, String param4,
                                        String param5){
    loadData(param1, param2, param3, param4, param5);

    return data;
}

private void loadData(String param1, String param2, String param3, String param4,
                              String param5){
    Retrofit retrofit = HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
    logging.setLevel(HttpLoggingInterceptor.Level.BODY);

    OkHttpClient okHttpClientGet = new OkHttpClient.Builder()
            .addInterceptor(logging)
            .build();

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(ScalarsConverterFactory.create())
            .client(okHttpClientGet)
            .build();
    ApiInterface apiInterface = retrofit.create(ApiInterface.class);

    Call<String> call = apiInterface.fetchData(param1, param2, param3, param4, param5);

    call.enqueue(new Callback<String>() {
        @Override
        public void onResponse(Call<String> call, Response<String> response) {
            if(response.isSuccessful()){
                Log.v(TAG, "onResponse: " + response.body());
                data.postValue(response.body());
            }else{
                try {
                    String errorBody = response.errorBody().string();
                    Log.e(TAG, "onResponse: " + errorBody);
                    data.postValue(errorBody);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }

        @Override
        public void onFailure(Call<String> call, Throwable t) {
            Log.e(TAG, "onFailure: " + t.getMessage());
        }
    });
}

FragmentTest(这是我定义的一个函数,点击一个按钮就会被调用)

viewmodelData.getData("param1", "param2", "param3",
            "param4", "param5")
                .observe(getViewLifecycleOwner(), new Observer<String>() {
            @Override
            public void onChanged(String s) {
                Log.v("TAG", "onChanged: " + s);

                Gson gson = new Gson();
                JsonObject root = gson.fromJson(s, JsonObject.class);
                
                //parsing response...
            }
        });

ViewModel 实例已创建为:

viewmodelData = new ViewModelProvider(this).get(ViewModelData.class);

我很感激任何帮助,因为我已经坚持了一段时间了。

您的流程正在为同一个 LiveData 添加多个观察者,这可能会导致您看到的问题。

在每次单击按钮时,您都会(再次)观察 getData() 返回的 LiveData 对象。

将您的 getData 方法更改为:

public LiveData<String> getData() {
    return data;
}

并使您的 loadData 方法 public:

public void loadData(String param1, String param2, String param3, String param4, String param5) {
   ...
}

在您片段的 onCreateView() 中为您的 LiveData 添加一个观察者:

viewmodelData
    .getData()
    .observe(getViewLifecycleOwner(), new Observer<String>() {
        @Override
        public void onChanged(String s) {
            Log.v("TAG", "onChanged: " + s);

            Gson gson = new Gson();
            JsonObject root = gson.fromJson(s, JsonObject.class);
            
            //parsing response...
        }
    });

这确保您的 LiveData 仅由单个观察者观察和处理。

点击按钮后,调用:

viewmodelData.loadData("param1", "param2", "param3", "param4", "param5");