概述:我有一个聊天应用程序。到目前为止,我一直在使用带有Listview的CursorAdapter来加载列表中的聊天项目。但现在,我计划重构代码,将RecyclerView与RecyclerView.Adapter和类似whatsapp的"加载更多"功能一起使用。
问题:内存消耗。使用CursorAdapter,不在可视区域中的项目会被垃圾回收,但现在由于我使用的是CustomModal的ArrayList,一旦你加载了列表中的所有项目(通过单击"加载更多"按钮),我就会在内存日志中看到高内存消耗(无垃圾回收)。
我的猜测是,现在我正在加载ArrayList中的所有项目,这就是问题的原因。就是这样吗?
有没有一种方法可以避免问题或优化问题?
编辑 :不能在这里发布完整的代码,但这里是我实现的适配器的一个片段:
public class MessageAdapter extends RecyclerView.Adapter<MessageAdapter.MyViewHolder> {
private ArrayList<MyModal> mMyModals;
public MessageAdapter(ArrayList<MyModal> mMyModals) {
this.mMyModals = mMyModals;
//... Some fields initialization here
}
public void changeList(ArrayList<MyModal> myModals, boolean isLoadMoreEnabled){
this.mMyModals = myModals;
//... Some fields initialization here
notifyDataSetChanged();
}
public void toggleLoadMore(boolean isLoadMoreEnabled){
if(isLoadMoreEnabled){
//..Checks if load more is already enabled or not
//..If not then enables it by adding an item at 0th poition of MyModal list
//..Then notifyDataSetChanged()
}else{
//..Checks if load more is already disabled or not
//..If not then disables it by removing an item at 0th poition of MyModal list
//..Then notifyDataSetChanged()
}
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
MyViewHolder messageViewHolder = null;
View itemLayoutView = null;
MyModal.MessageType messageType = MyModal.MessageType.getMessageTypeFromValue(viewType);
switch (messageType){
case MESSAGE_TYPE1:
itemLayoutView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.layout1, null);
messageViewHolder = new Type1ViewHolder(itemLayoutView);
break;
case MESSAGE_TYPE2:
itemLayoutView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.layout2, null);
messageViewHolder = new Type2ViewHolder(itemLayoutView);
break;
}
return messageViewHolder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
final MyModal myModal = mMyModals.get(position);
MyModal.MessageType messageType = myModal.getMessageType();
holder.initialize(myModal);
}
@Override
public int getItemCount() {
return (mMyModals != null)?mMyModals.size():0;
}
@Override
public int getItemViewType(int position) {
return mMyModals.get(position).getMessageType().getValue();
}
public abstract class MyViewHolder extends RecyclerView.ViewHolder {
public MyViewHolder(View itemLayoutView) {
super(itemLayoutView);
}
public abstract void initialize(MyModal myModal);
}
class Type1ViewHolder extends MyViewHolder {
//...Variables
public Type1ViewHolder(View itemLayoutView) {
super(itemLayoutView);
//...variables initialization here
}
@Override
public void initialize(MyModal myModal) {
//...Setting values in view using myModal
}
}
class Type2ViewHolder extends MyViewHolder {
//...Variables
public TextViewHolder(View itemLayoutView) {
super(itemLayoutView);
//...variables initialization here
}
@Override
public void initialize(MyModal myModal) {
//...Setting values in view using myModal
}
}
}
首先:
public void changeList(ArrayList<MyModal> myModals, boolean isLoadMoreEnabled){
this.mMyModals = myModals;
//... Some fields initialization here
notifyDataSetChanged();
}
在这里,您正在创建一个新的数组列表,并将其分配给您的mMyModals。这意味着此时有2个数组,它们占用的空间是所需空间的两倍。GC并没有按照你期望的方式工作。由于arraylist是在你的活动中初始化的,只要arraylist持续存在,它就会一直存在,初始arraylist也是如此。
而不是在活动中创建一个新的arraylist并将其传递给changeList。只要清除你的旧arraylist并通过它。此外,在适配器changeList方法中,您可以执行以下
public void changeList(ArrayList<MyModal> myModals, boolean isLoadMoreEnabled){
this.mMyModals.clear();
this.mMyModels.addAll(myModels);
//... Some fields initialization here
notifyDataSetChanged();
}
如果我不清楚,请告诉我。如果不起作用,还显示您的活动代码。
不要替换整个ArrayList
并调用notifyDataSetChanged
,而是尝试将项添加到ArrayList
,然后调用notifyItemRangeInserted(int positionStart, int itemCount)
,也许这样可以。此外,您不必更换Adapter
的ArrayList
。您的Activity
/Fragment
可能具有相同的ArrayList
,只需在Activity
/Fragment
中编辑此列表,然后调用notifyItemRangeInserted(int positionStart, int itemCount)
即可。此外,您也可以尝试只获取下一个X数量的消息,而不是检索所有消息,这样您就不会检索以前已经检索到的消息(如果您还没有这样做的话)。