2016-04-08 3 views
2

Übersicht: Ich habe eine Chat-Anwendung. Bis jetzt benutzte ich CursorAdapter mit einer Listview, um meine Chat-Elemente in die Liste zu laden. Aber jetzt plane ich, den Code zu refactorView mit RecyclerView.Adapter und eine "Mehr laden" -Funktionalität wie WhatsApp zu refaktorieren.Große Anzahl von Artikeln in RecyclerView.Adapter - Speicher Ausgabe

Ausgabe: Speicherverbrauch. Mit CursorAdapter erhielten Objekte, die nicht im sichtbaren Bereich waren, Garbage Collected, aber jetzt, da ich eine ArrayList meines CustomModals verwende, sobald ich alle Elemente in der Liste lade (indem ich auf die Schaltfläche "Load More" klicke), sehe ich hoher Speicherverbrauch in den Speicherprotokollen (No Garbage Collection).

Meine Vermutung ist jetzt, ich lade alle Elemente in einer ArrayList und das verursacht das Problem. Ist es das?

Gibt es eine Möglichkeit, das Problem zu vermeiden oder das Problem zu optimieren?

EDIT: Kann den vollständigen Code hier nicht schreiben, aber hier ist ein Ausschnitt aus der Art von Adapter, die ich umgesetzt habe:

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 
     } 
    } 
} 
+0

Können Sie Ihre Adapterklasse zeigen. Vielleicht initiieren Sie mehr als nötig. Überprüfen Sie sobald Sie Code –

+0

Hallo Ragesh, habe ich meine Frage mit dem Code aktualisiert. Können Sie mir bitte helfen, das Problem hier zu lösen? – Wanted

Antwort

1

Zu allererst:

public void changeList(ArrayList<MyModal> myModals, boolean isLoadMoreEnabled){ 
    this.mMyModals = myModals; 
    //... Some fields initialization here 
    notifyDataSetChanged(); 
} 

Hier werden Sie eine neue Arraylist zu schaffen und es zu Ihrem mMyModals zuweisen. Dies bedeutet, dass es an diesem Punkt 2 Arraylisten gibt, die doppelt so viel Platz benötigen wie benötigt. GC funktioniert nicht so, wie Sie es erwarten. Da die Arraylist in Ihrer Aktivität initialisiert wird, wird sie so lange bestehen bleiben, wie die Arraylist persistiert, ebenso wie die ursprüngliche Arraylist.

Anstatt eine neue Arraylist in Ihrer Aktivität zu erstellen und sie an changeList zu übergeben. Sie einfach Ihre alte Arraylist löschen und that.And auch in Adapter changelist-Methode übergeben Sie das unten tun können

 public void changeList(ArrayList<MyModal> myModals, boolean isLoadMoreEnabled){ 
    this.mMyModals.clear(); 
    this.mMyModels.addAll(myModels); 
    //... Some fields initialization here 
    notifyDataSetChanged(); 
} 

Bitte lassen Sie mich wissen, wenn ich nicht klar bin. Zeigen Sie auch Ihren Aktivitätscode, wenn dies nicht funktioniert.

+0

Dank @Ragesh, werde es morgen versuchen. – Wanted

+0

Das (clear() und addAll() Methode) hat tatsächlich funktioniert. Zumindest ist GC in der Lage, jetzt zu arbeiten. Danke noch einmal. – Wanted

+0

Dann markieren Sie es bitte als korrekt. –

1

Statt die ganze ArrayList ersetzen und Rufen Sie notifyDataSetChanged, versuchen Sie, die Elemente zu der ArrayList hinzufügen und dann notifyItemRangeInserted(int positionStart, int itemCount) anrufen, vielleicht könnte das funktionieren. Außerdem müssen Sie die AdapterArrayList nicht ersetzen. Ihr Activity/Fragment hat wahrscheinlich die gleiche ArrayList, nur diese Liste in Ihrem Activity/Fragment bearbeiten und dann notifyItemRangeInserted(int positionStart, int itemCount) anrufen sollte den Trick tun. Anstatt alle Nachrichten abzurufen, können Sie auch versuchen, nur die nächste Menge an Nachrichten zu erhalten, sodass Sie die Nachrichten, die Sie bereits abgerufen haben, nicht mehr abrufen können (falls Sie dies nicht bereits getan haben).

+0

Danke Jeffalee, werde es ausprobieren. Wenn ich jedoch meiner Arraylist-Referenz ein neues Objekt zuweise, wird das alte Objekt für GC zugelassen, richtig? Aber das sehe ich nicht. Meine App verbraucht die kompletten 128 MB Speicher – Wanted

Verwandte Themen