带有 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来防止因恢复片段而导致的冗余打印
我有以下改造客户端的实现:
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来防止因恢复片段而导致的冗余打印