使用Dagger+RxJava更新RecyclerView时列表无限刷新问题排查
看起来你的代码里藏着一个无限循环触发网络请求的坑,这才导致列表每秒都刷新一次。我来帮你把问题拆解开:
核心问题:无限循环调用loadData()
仔细看你的ContactsViewModel代码:
fun getContactMutableLiveData(): MutableLiveData<List<ContactsModel>> { loadData() // 每次调用这个方法都会触发一次网络请求 return mutableLiveData } // 请求成功的回调里: override fun onSuccess(t: List<ContactsModel>) { getContactMutableLiveData().value = t // 这里调用了getContactMutableLiveData(),又会触发loadData() }
当第一次网络请求成功后,你通过getContactMutableLiveData().value = t更新LiveData,但这个方法内部会再次调用loadData()发起新请求。新请求成功后又重复这个流程,直接形成了无限循环——每完成一次请求就立刻开启下一次,所以日志会显示每秒刷新一次(对应每次网络请求的响应周期)。
而你的Java项目里应该是直接给LiveData赋值,没有通过getContactMutableLiveData()方法,所以没触发这个循环。
修复方案
首先解决最核心的循环问题,修改onSuccess里的代码,直接给mutableLiveData赋值,绕开getContactMutableLiveData():
override fun onSuccess(t: List<ContactsModel>) { mutableLiveData.value = t // 直接设置LiveData的值,不再触发新的请求 }
另外还有几个优化建议,让代码更健壮:
避免重复创建Adapter和LayoutManager:你的Activity观察者回调里,每次数据更新都重新创建Adapter、设置LayoutManager,这完全没必要。建议在
onCreate里一次性初始化布局和Adapter,只在回调里更新数据:// Activity的onCreate中初始化一次 recycler_contacts.layoutManager = LinearLayoutManager(applicationContext, OrientationHelper.VERTICAL, false) recycler_contacts.setHasFixedSize(true) mAdapter = ContactsAdapter(this@ContactListActivity, arrayListOf()) recycler_contacts.adapter = mAdapter // 观察者回调里只更新数据 contactsViewModel.getContactMutableLiveData().observe(this@ContactListActivity, Observer { mAdapter.updateData(it as ArrayList<ContactsModel>) mAdapter.sortByName() })记得在
ContactsAdapter里添加updateData方法,更新数据集后调用notifyDataSetChanged()(用DiffUtil做局部刷新会更高效)。清理ViewModel的Disposable:重写
onCleared()方法清空订阅,避免内存泄漏:override fun onCleared() { super.onCleared() disposable.clear() }避免重复发起请求:修改
getContactMutableLiveData(),只有当LiveData为空时才加载数据:fun getContactMutableLiveData(): MutableLiveData<List<ContactsModel>> { if (mutableLiveData.value.isNullOrEmpty()) { loadData() } return mutableLiveData }
这样修改后,无限循环的问题就解决了,列表只会在首次启动时加载一次数据,后续有需要时再触发更新。
内容的提问来源于stack exchange,提问作者Infernal

