Speicherüberlauf bei ListView mit eigenem SimpleCursorAdapter

  • Antworten:2
  • Bentwortet
Roman
  • Forum-Beiträge: 20

29.07.2012, 17:45:34 via Website

Hallo zusammen,

kurz eine Schilderung wie sich alles entwickelt hat.
Ich ziehe Informationen aus einer Datenbank, die ich in einer ListView anzeigen möchte. Binde ich den Cursor normal an einen SimpleCursorAdapter, kann ich beliebig in der ListView scrollen. Da ich in der Abfrage aber Zwischensummen per Sub-Selects bilde, die natürlich nicht in jeder Zeile auftreten, möchte ich ggf. die TextViews, welche die Zwischensummen darstellen, ausblenden können.
Da ich für den SimplecursorAdapter nur die Methode setViewBinder() gefunden habe, die zwar irgendwie in der Lage ist die Werte der TextViews zu speichern aber keine weiteren Eigenschaften, habe ich schließlich eine Klasse mit einem eigenen Adapter zu Hilfe gezogen.

Der Code der Klasse sieht folgendermaßen aus:
[code]public class C_mySimpleCursorAdapter extends SimpleCursorAdapter {

private Context _Context;
private Cursor _Cursor;
private String[] _Columns;
private int[] _TextViews;
private int _Layout;


public C_mySimpleCursorAdapter(Context context, int layout, Cursor c,
String[] from, int[] to) {
super(context, layout, c, from, to);
// TODO Auto-generated constructor stub
this._Context = context;
this._Layout = layout;
this._Cursor = c;
this._Columns = from;
this._TextViews = to;
}


@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater theInflater = (LayoutInflater) _Context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

View listViewEntry = theInflater.inflate(_Layout, parent, false);
TextView tv_Content;

_Cursor.moveToPosition(position);

for (int i = 0; i < _TextViews.length; i++) {
tv_Content = (TextView) listViewEntry.findViewById(_TextViews[i]);
tv_Content.setText(_Cursor.getString(i + 1));

if (_Cursor.getString(i + 1).equals("%")) {
tv_Content.setHeight(0);
}
}

return listViewEntry;

};
}
[/code]


Prinzipiell funktioniert das vom Aussehen her wie ich das möchte, wie ich im Titel aber schon schreibe, kommt es zu einem Speicherüberlauf und zwar wenn man fleißig auf und ab scrollt.
In der Activity rufe ich den Adapter per

1mySCA = new C_mySimpleCursorAdapter(this, R.layout.listelayout, listeCursor, anzeigeSpalten, anzeigeViews);
2 lv_Liste.setAdapter(mySCA);

auf. Nun mein Frage, warum läuft der Speicher hier über? Ich bilde doch nur ein Objekt der Klasse und vermute daher, dass es irgendetwas mit der überschriebenen getView()-Methode zu tun hat, bin aber ratlos.

Schöne Grüße aus der Eifel,

Roman

P.S. wie füge ich denn den Code richtig ein? Ich klicke auf das Icon im Editorkopf und füge dann per copy + paste den Code aus Eclipse zwischen [.code][./code] ein...kommt aber in der Vorschau bei der Klasse nur eine "Quellcode-Wurst" raus obwohl es im Editor richtig angezeigt wird, bei der Beschreibung des Adapter-Aufrufs funktioniert es hingegen.

Antworten
Ansgar M
  • Forum-Beiträge: 1.544

30.07.2012, 11:00:37 via App

Hey,

kann es sein, dass du irgendwie eine Referenz auf diese Views hältst? Du solltest am besten die convertView benutzen, die dir übergeben wird und nicht jedes Mal eine neue View erzeugen.

Lg Ansgar

Antworten
Roman
  • Forum-Beiträge: 20

30.07.2012, 20:22:14 via Website

Hallo Ansgar,

danke für deine Antwort. Nach der Arbiet wollte Ich mich nochmal mit dem eigenen Adapter auseinandersetzen und da kam mir dein Posting gerade recht.
Die Row habe ich jedesmal neu zeichnen lassen weil ich ja ggf. die ein oder andere TextView ausblenden woltle. Zum Testen, ob der Speicherfehler was mit den endlos neuen Rows zu tun hat, habe ich aber umgestellt auf

1...
2View listViewEntry;
3if (convertView == null) {
4 listViewEntry = ...
5} else {
6 listViewEntry = convertView;
7}
8...

Also qausi wie du schon sagtest, die Row wiederverwenden. Hierbei hat die ListView fehlerfrei funktioniert. Im LogCat stehen bei der Version mit stets neuen Rows übrigens endlose 'Grow heap' Meldungen, selten nur wird Speicher wieder freigegeben - bis es halt zum unvermeidlichen Überlauf kommt.

Beim Wiederverwenden hatte ich ja nun wieder das Problem, dass eine Änderung (scheinbar) für jede TextView in einer Row übernommen wird. Scheinbar deshalb, weil ich ja die Höhe auf 0 setze und niemals wieder zurückgesetzt habe. Darin lag also auch mein ursprüngliches Problem begründet, weshalb ich überhaupt einen eigenen Adapter genommen habe.

Mit dieser Erkenntnis habe ich dann nochmal direkt in der Activity einen SimpleCursorAdapter erstellt und nochmal die setViewBinder Methode genutzt, um die entsprechenden TextViews ggf. auszublenden.

1listeAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
2@Override
3public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
4TextView tv_Content = (TextView) view;
5if (cursor.getString(columnIndex).equals("%")) {
6tv_Content.setHeight(0);
7} else {
8tv_Content.setHeight(30);
9}
10return false;
11}
12});

Und siehe da, über diese Methode werden wohl doch auch andere Eigenschaften gespeichert wenn man kein Pfosten ist :-).
Die '30' als Wert war jetzt nur zum Testen und wird dann noch ersetzt, aber eins nach dem anderen .

Schöne Grüße aus der Eifel,

Roman

Antworten