Dynamisches Menu saugt zuviel Speicher

kuzdu

Aktives Mitglied
Hallo liebe Leute,

ich habe eine App geschrieben bei der man am Startbildschirm eine Auswahl von Kategorien präsentiert bekommt in Form von Buttons. Diese erzeuge ich dynamisch.
Das hat für mich den Vorteil, dass wenn ich eine weitere Kategorie hinzufügen möchte, nur die Schleife erhöhen muss.

Inzwischen habe ich allerdings soviele Kategorien zur Auswahl, dass das Menuerzeugen je nach Handy einige Sekunden dauert. Es ist also eine deutliche Verzögerung zu bemerken. Gerade auf ältereren Geräten ( z.B. Samsung Galaxy S2) ist es nicht wirklich userfreundlich.

Nun meine Frage: wenn ich das XML statisch hinterlege, ist dieses Problem dann behoben? Für mich würde das zwar viel mehr Arbeit bedeuten, aber im Endeffekt soll die App ja flüssig laufen.
Oder kann ich das Erzeugen des Menus verbessern? Gibt es unterschiedlich gute Methoden?
Könnte auch die Bildergröße relevant sein? Ich halte die Bildgröße so gering wie möglich, allerdings muss eine gewissen Qualität ja auch vorhanden sein.

Hatte jmd. von euch schonmal ein ähnliches Problem?

Die Buttons erzeuge ich so:
Java:
for (int row = 0; row < numRows; row++) {

		        TableRow tableRow = new TableRow(this);
			tableRow.setLayoutParams(new TableLayout.LayoutParams(
					TableLayout.LayoutParams.MATCH_PARENT,
					TableLayout.LayoutParams.WRAP_CONTENT, 0.5f));

			table.addView(tableRow);

			for (int col = 0; col < numCols; col++) {

				if (countButton <= datasource.getNumberOfDifferentKategories()) {

					final Button btn = new Button(this);
					btn.setLayoutParams(new TableRow.LayoutParams(
							TableRow.LayoutParams.MATCH_PARENT,
							TableRow.LayoutParams.WRAP_CONTENT, 0.5f));

					btn.getLayoutParams().width = width;
					btn.getLayoutParams().height = height;
					btn.setId(countButton);
					btn.setTextColor(Color.parseColor("#ffffff"));
					btn.setTextSize(17);


					// Weist Kategorien ihre Bilder zu
					if (menubuttonChange == 1) {
						btn.setBackgroundResource(R.drawable.bild1);
					}//... hier werden natürlich 1-39 Bilder abgefragt, je nach dem welches hinterlegt werden soll
					}else if (menubuttonChange == 39) {
						btn.setBackgroundResource(R.drawable.bild39);
					} else {
						btn.setBackgroundResource(R.drawable.defaultbild);
					}
					
					btn.setEnabled(true);
					// }

					btn.setText("\n \n \n \n" + categoryName + "\n");


		   btn.setOnClickListener(new View.OnClickListener() {

						@Override
						public void onClick(View v) {
							//klickbar der Button
						}

					});

		}
	}

Freundliche Gruß
 
Zuletzt bearbeitet von einem Moderator:

stg

Top Contributor
Das konzeptuelle Design hinterfragen wir erstmal nicht, auch wenn das sicherlich wesentlich eleganter lösbar ist. denn dein riesiges if-else-und-Schleifen-Konstrukt ist zwar nicht schön, tut aber auch nicht weh, was Laufzeit angeht... Das einzige, was ich hier sehe, das Probleme bereiten könnte, sind tatsächlich die Hintergrundbilder. Nimm die doch mal raus und setze stattdessen einfach nur eine Farbe oder lass das setzen des Hintergrunds auch mal ganz weg. Läuft es dann flüssig? Wenn ja, dann weißt du ja, wo du ansetzen musst.
Ansonsten wäre ggfls noch interessant zu wissen, was "datasource.getNumberOfDifferentKategories()" genau macht. Sofern erstere Variante nicht den gewünschten Erfolg hat, könnte ich mir hier auch noch ein bottleneck denken.
 

kuzdu

Aktives Mitglied
Hey,
das mit den Bildern teste ich gleich mal, wenn ich zu Hause bin.

datasource.getNumberOfDifferentCategories(); macht nichts besonderes, aber du könntest recht haben.

Ich habe eine Tabelle mit circa 3500 Begriffen. Jeder Begriff ist einer Kategorie zugeordnet. Der Datenbankbefehl fragt jetzt (wie mir auffällt jedes Mal) nach den unterschiedlichen Kategorien von den ganzen Begriffen mittels GROUP BY.
Das werde ich auf jeden Fall zwischenlagern und berichten.

Angenommen es liegt an den Bilder, was könnte ich da tun? Die Bilder sind essentiell für das Design und auch nicht größer als 50 KB. Wenn ich sie noch kleiner mache, sehen sie verzerrt und pixelig aus.

Danke auf jeden Fall schon mal :)
 

stg

Top Contributor
datasource.getNumberOfDifferentCategories(); macht nichts besonderes, aber du könntest recht haben.

Ich habe eine Tabelle mit circa 3500 Begriffen. Jeder Begriff ist einer Kategorie zugeordnet. Der Datenbankbefehl fragt jetzt (wie mir auffällt jedes Mal) nach den unterschiedlichen Kategorien von den ganzen Begriffen mittels GROUP BY.
Das werde ich auf jeden Fall zwischenlagern und berichten.

Das heißt also, dass du für jeden Button eine eigene Anfrage an die Datenbank schickst? (davon war in deinem ursprünglichen Post nichts zu lesen) Wenn das der Fall ist, dann ist das auch ein absolutes No-Go. Baue dir ein geeignetes Datenmodel auf und initialisiere die Daten, die aus der Datenbank benötigt werden, einmalig und (soweit wie nötig) vollständig in (im Idealfall) nur einer einzigen Datenbank-Abfrage. Um dir die Arbeit zu erleichtern kannst du dir dafür ja ggfls entsprechende Views und Prozeduren auf der Datenbankseite erstellen.
 

kuzdu

Aktives Mitglied
Das heißt also, dass du für jeden Button eine eigene Anfrage an die Datenbank schickst? (davon war in deinem ursprünglichen Post nichts zu lesen)

Ja! Es war nichts davon zu lesen, weil ich anscheinend völlig betriebsblind dieses Menu gebaut habe. I'm sorry ;) Also ich habe es ersetzt, in dem ich die die datasource.getNumberOfDifferentCategories(); ausgelagert habe und nur einmal aufrufen lassen.
Eine Verschnellerung gab es schon, aber nicht die, die ich gewollt habe.

Allerdings gibt es neue Erkenntnisse:
Angenommen ich klicke auf Kategorie1, wenn ich zurückklicke mit einem Zurückbutton, um aufs Hauptmenu zu gelangen, baut er das Menu wieder komplett neu auf.
Wenn ich dagegen den Zurückpfeil von meinem Handy nehme, dann scheint auf einen Cache zurückgegriffen zu werden.

Nun aber zu einem weiteren Problem:
Der Zurückbutton hat schon seine Berechtigung, weil er Threads und Prozesse beendet. Dementsprechend habe ich den standardmäßigen Zurückpfeil auf der Handytastatur onBackPressed() überschrieben.

Hier der Code:

Code:
	// Verhindert den Standard-Zurueckpfeil bei Androidgeräten
	@Override
	public void onBackPressed() {
		goBackToMainMenu();
	}

	// Geht zurueck in die Main-Methode und beendet ggf. alle Threads bzw. den
	// Beschleunigssensor
	private void goBackToMainMenu() {
		unregisterTheSensor();
		Intent intent = new Intent(getApplicationContext(), MainActivity.class);
		intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
		startActivity(intent);
	}

	// deaktiviert den Beschleunigungssensor
	private void unregisterTheSensor() {
		sm.unregisterListener(this);
	}

Durchs Intent scheint die MainActivity sich nochmal komplett neu aufzubauen. Das dauert wieder. Bilder bzw. weitere Datenbankzugriffe haben nichts mehr damit zu tun. Ich habe alles einmal auskommentiert und nur "stumpfe Buttons" benutzt. Vielleicht dauert es einfach so lange 50 Buttons in einem Tablelayout zu erstellen?

Also meine neue Frage: Gibt es eine Möglichkeit, eventuell gestartete Prozesse (sauber) zu beenden und trotzdem auf das Mainmenu zurückzugelangen, ohne, dass die MainActivity wieder neu aufgebaut wird?

Oder fällt einem eine ganz andere Vorgehensweise ein? Ich bin für alles offen. :)

Gruß

PS:Alternativ bin ich natürlich auch für MainActivity-Menuoptimierungen dankbar :)
 

kuzdu

Aktives Mitglied
Also ich habe jetzt doch mal ein Design mit statischem XML erstellt und tatsächlich ist dieses deutlich schneller.

Der Übergang hat vorher auf meinem Motorolo Moto G (1rst Generation) 2100 ms gedauert, nun dauert er nur noch 400ms.

Werde wohl nun überall ein statisches XML hinterlegen. (Ist zwar für mich mehr Arbeit, aber darum geht es in der Hinsicht ja nicht. :D)

Für die, die es interessiert: Auf englisch findet man mehr zu dieser Problematik: performance dynamically buttons android (table)

So wie ich es verstehe, wird empfohlen auf ein statisches XML auszuweichen oder den Erstellungsprozess in einen Thread auszulagern, falls möglich.
 

Ähnliche Java Themen


Oben