真机从导航键恢复应用时onResume卡顿及RecyclerView重复加载求助
问题描述
真机测试应用时,onStart阶段运行正常,但将应用置于onPause状态打开其他应用后,点击导航键恢复应用时响应迟缓,存在约1秒延迟,且每次恢复应用时,Fragment中的RecyclerView都会重新加载。
相关代码(ChatListFragment.kt)
class ChatListFragment : Fragment() { private lateinit var binding: FragmentChatListBinding private var chatList = ArrayList<Chats>() private var user: Chats?= null private var chatListAdapter = ChatListAdapter(chatList) private lateinit var auth: FirebaseAuth private lateinit var storage: FirebaseStorage private lateinit var firestore: FirebaseFirestore override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // Inflate the layout for this fragment val view = inflater.inflate(R.layout.fragment_chat_list, container, false) binding = FragmentChatListBinding.inflate(layoutInflater) init() addContacts() changeListener() // Calling the override functions from // the Linear Layout Manager inner class val myLinearLayoutManager = object : LinearLayoutManager(context) { override fun canScrollVertically(): Boolean { return false } } view.popChatsRec.layoutManager = myLinearLayoutManager view.popChatsRec.adapter = chatListAdapter chatList.clear() return view } private fun addContacts(){ val firebaseUser = auth.currentUser if (firebaseUser != null){ firestore.collection("Contacts").document(auth.currentUser?.uid!!).collection("rooms").get() .addOnSuccessListener { if (!it.isEmpty){ for (documents in it.documents){ val uId = documents.data?.get("uId").toString() val uName = documents.data?.get("fullName").toString() val uNum = documents.data?.get("fullNum").toString() val uStatus = documents.data?.get("status").toString() val uPresence = documents.data?.get("presence").toString() val uImg = documents.data?.get("image").toString() chatList.add(Chats(uId, uImg, uName, "", uNum, uStatus, uPresence)) } } else { Toast.makeText(context, "FailedHere", Toast.LENGTH_SHORT).show() } chatListAdapter.notifyDataSetChanged() }.addOnFailureListener { Toast.makeText(context, "FailureOverall", Toast.LENGTH_SHORT).show() } } else{ Toast.makeText(context, "Null", Toast.LENGTH_SHORT).show() } } private fun changeListener(){ firestore.collection("Contacts").document(auth.currentUser?.uid!!).collection("rooms") .addSnapshotListener { snapshots, e-> if (e != null){ Log.w(ContentValues.TAG, "listen:error", e) return@addSnapshotListener } for (dc in snapshots!!.documentChanges) { if (dc.type == DocumentChange.Type.MODIFIED) { chatList.clear() addContacts() Log.d(ContentValues.TAG, "New city: ${dc.document.data}") } } } } private fun init(){ auth = FirebaseAuth.getInstance() storage = FirebaseStorage.getInstance() firestore = Firebase.firestore } }
问题原因与修复方案
核心问题点
- RecyclerView重复加载:
onCreateView在Fragment恢复时会重新执行,你在这里直接调用addContacts()触发全量数据请求,同时末尾的chatList.clear()会清空刚加载的数据,导致重复加载+界面空白。 - 恢复响应迟缓:每次恢复都重新发起Firestore网络请求,加上全量刷新UI,双重耗时导致卡顿;另外SnapshotListener未绑定生命周期,可能造成内存泄漏加重性能负担。
具体修复步骤
1. 调整数据加载时机,避免重复请求
把数据初始化逻辑移到onViewCreated,并判断列表是否为空再加载,同时移除onCreateView里的chatList.clear():
override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { binding = FragmentChatListBinding.inflate(inflater, container, false) // 提前设置LayoutManager和Adapter val myLinearLayoutManager = object : LinearLayoutManager(context) { override fun canScrollVertically(): Boolean { return false } } binding.popChatsRec.layoutManager = myLinearLayoutManager binding.popChatsRec.adapter = chatListAdapter return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) init() // 仅列表为空时才加载数据,避免重复请求 if (chatList.isEmpty()) { addContacts() } changeListener() }
2. 优化SnapshotListener的生命周期与更新逻辑
绑定Fragment生命周期自动管理监听,且只更新修改的条目,而非全量刷新:
private fun changeListener(){ firestore.collection("Contacts").document(auth.currentUser?.uid!!).collection("rooms") // 绑定View生命周期,Fragment销毁时自动取消监听 .addSnapshotListener(viewLifecycleOwner) { snapshots, e-> if (e != null){ Log.w(ContentValues.TAG, "listen:error", e) return@addSnapshotListener } for (dc in snapshots!!.documentChanges) { if (dc.type == DocumentChange.Type.MODIFIED) { // 找到修改的条目并局部更新 val targetId = dc.document.getString("uId") val index = chatList.indexOfFirst { it.uId == targetId } if (index != -1) { val updatedChat = dc.document.toObject(Chats::class.java) updatedChat?.let { chatList[index] = it chatListAdapter.notifyItemChanged(index) } } } } } }
3. 用DiffUtil优化Adapter刷新性能
替换notifyDataSetChanged为DiffUtil,减少不必要的UI重绘:
// 修改ChatListAdapter class ChatListAdapter(private val chatList: MutableList<Chats>) : RecyclerView.Adapter<ChatListAdapter.ViewHolder>() { // ... 原有ViewHolder等代码 fun updateData(newList: List<Chats>) { val diffCallback = ChatDiffCallback(chatList, newList) val diffResult = DiffUtil.calculateDiff(diffCallback) chatList.clear() chatList.addAll(newList) diffResult.dispatchUpdatesTo(this) } class ChatDiffCallback(private val oldList: List<Chats>, private val newList: List<Chats>) : DiffUtil.Callback() { override fun getOldListSize() = oldList.size override fun getNewListSize() = newList.size override fun areItemsTheSame(oldPos: Int, newPos: Int): Boolean { return oldList[oldPos].uId == newList[newPos].uId } override fun areContentsTheSame(oldPos: Int, newPos: Int): Boolean { return oldList[oldPos] == newList[newPos] } } }
然后修改addContacts里的刷新逻辑:
private fun addContacts(){ val firebaseUser = auth.currentUser if (firebaseUser != null){ firestore.collection("Contacts").document(auth.currentUser?.uid!!).collection("rooms").get() .addOnSuccessListener { result -> val newChats = mutableListOf<Chats>() if (!result.isEmpty){ result.documents.forEach { doc -> doc.toObject(Chats::class.java)?.let { newChats.add(it) } } } else { Toast.makeText(context, "暂无联系人", Toast.LENGTH_SHORT).show() } chatListAdapter.updateData(newChats) }.addOnFailureListener { Toast.makeText(context, "加载联系人失败", Toast.LENGTH_SHORT).show() } } else{ Toast.makeText(context, "用户未登录", Toast.LENGTH_SHORT).show() } }
4. 修复重复View绑定问题
原代码同时使用inflater.inflate和FragmentChatListBinding.inflate,属于重复操作,统一用ViewBinding即可,减少资源浪费。
内容的提问来源于stack exchange,提问作者Mahmoud Nabil
相关产品推荐
相关产品推荐

