带有 liveData 的 Retrofit2 使 api 第二次调用两次,第三次调用三次,依此类推

Retrofit2 with liveData makes api calls twice the second time they are called, three times the third etc

我有以下改造客户端的实现:

private val retrofitClient: Retrofit.Builder by lazy {

    val interceptor = HttpLoggingInterceptor()
    interceptor.level = HttpLoggingInterceptor.Level.HEADERS

    val okHttpClient = OkHttpClient.Builder().addNetworkInterceptor(interceptor)
        .cookieJar(SessionCookieJar())
        .connectTimeout(15, TimeUnit.SECONDS)
        .readTimeout(20, TimeUnit.SECONDS)
        .writeTimeout(20, TimeUnit.SECONDS)
        .retryOnConnectionFailure(true)

    Retrofit.Builder()
        .baseUrl(URLWebConstants.BASE_URL)
        .client(okHttpClient.build())
        .addConverterFactory(GsonConverterFactory.create())
}

val postYotiApiService: PostYotiAPIService by lazy {
    retrofitClient.build().create(PostYotiAPIService::class.java)
}

interface PostYotiAPIService {
    @POST("*url*")
    fun postYoti(): Call<PostYotiResponse>
}

然后我有一个 MainActivityRepository class 调用内容:

class MainActivityRepository() {

val client = RetrofitClient

var postYotiLiveData = MutableLiveData<YotiData?>()
fun postYoti(): MutableLiveData<YotiData?> {
    val myCall = client.postYotiApiService.postYoti()

    myCall.enqueue(object : Callback<PostYotiResponse> {
        override fun onFailure(call: Call<PostYotiResponse>, t: Throwable) {
            Log.d("Retrofit", "Something went wrong", t)
        }

        override fun onResponse(
            call: Call<PostYotiResponse>,
            response: Response<PostYotiResponse>
        ) {
            if (response.isSuccessful) {
                postYotiLiveData.postValue(response.body()!!.data)
            } else {
                postYotiLiveData.postValue(null)
            }
        }
    })
    return postYotiLiveData
}

然后在我的 Fragment 的 ViewModel 中,我这样调用函数:

val repository = MainActivityRepository()

fun postYoti(): MutableLiveData<YotiData?> {
    return repository.postYoti()
}

最后在我的片段中我这样调用:

btnYoti.setOnClickListener {
    viewModel.postYoti().observe(viewLifecycleOwner, {
                println("Hello World")
        }
    })
}

我第一次拨打电话时,一切正常,没有任何问题,Hello world 打印了一次。我第二次拨打 Hello world 时打印了两次,总共打印了 3 次。第三次 Hello World 打印了 3 次,当我设置断点时,我可以看到 println 被命中 3 次。每次点击只需调用一次。

您正在观察 onClickListener 中的实时数据!这意味着每次单击该按钮时,一个新的观察者(带有 viewLifecycleOwner)将附加到 liveData 并在片段的视图为 运行 时保持活动状态。所以每次点击都会添加另一个永远不会被删除的观察者,除非视图被销毁。当没有动作时使用观察(例如,您正在观察 onViewCreated 中的实时数据,它将始终收到任何更改的通知),在动作(如点击)上只需获取 LiveData 的值并对其进行处理。像这样

override fun onViewCreated(){
    //...
    btnYoti.setOnClickListener {
        viewModel.postYoti()
    }

    //Add a getter to your VM to prevent direct access to rep
 
  viewModel.repository.postYotiLiveData.observe(viewLifecycleOwner, {
                println("Hello World")
        }
    }
}

另一方面,您可以使用LiveEvent来防止因恢复片段而导致的冗余打印