Wie erzwinge ich eine Aktualisierung der gesamten Layoutansicht?


173

Ich möchte die Ansicht der Hauptlayoutressource zum Neuzeichnen / Aktualisieren erzwingen, z. B. die Activity.onResume () -Methode. Wie kann ich das machen ?

Mit der Hauptlayoutansicht meine ich die ('R.layout.mainscreen' unten), die in meiner Activity.onCreate () aufgerufen wird, wie folgt: -

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.mainscreen);
}

Haben Sie versucht, Ihr umschließendes Linear / Relative / WhateverLayout zu benennen, findViewById darauf aufzurufen und dann invalidate () aufzurufen? (Ich würde dies als Antwort setzen, aber ich weiß nicht, ob die Ungültigmachung von Eltern auch Kinder ungültig macht und ich bin nicht irgendwo, wo ich es testen kann.)
Ben Williams

Danke auch ! Ich kämpfe immer noch damit. Können Sie sich ansehen, was ich unten gepostet habe? Ich brauche diesen Code (oder einen anderen?), Damit mein Thema
aktualisiert wird

Antworten:


149

Um die Frage genau zu beantworten: Verwenden Sie invalidate ():

public void invalidate () Seit: API Level 1

Die gesamte Ansicht ungültig machen. Wenn die Ansicht sichtbar ist, wird onDraw (Canvas) zu einem späteren Zeitpunkt aufgerufen. Dies muss von einem UI-Thread aufgerufen werden. Rufen Sie postInvalidate () auf, um von einem Thread außerhalb der Benutzeroberfläche aufzurufen.

ViewGroup vg = findViewById (R.id.mainLayout);
vg.invalidate();

Wenn die Aktivität fortgesetzt wird, wird jede Ansicht dazu gebracht, sich selbst zu zeichnen. Es sollte kein Aufruf von invalidate () erforderlich sein. Stellen Sie zum Anwenden des Themas sicher, dass Sie dies tun, bevor eine Ansicht gezeichnet wird, dh vorhersetContentView(R.layout.mainscreen);

public void setTheme (int resid) Seit: API Level 1

Legen Sie das Basisthema für diesen Kontext fest. Beachten Sie, dass dies aufgerufen werden sollte, bevor Ansichten im Kontext instanziiert werden (z. B. bevor setContentView (View) oder inflate (int, ViewGroup) aufgerufen wird).

Die API-Dokumentreferenz finden Sie hier: http://developer.android.com/reference/android/view/ContextThemeWrapper.html#setTheme%28int%29

Da die onDraw () -Methode für bereits instanziierte Ansichten funktioniert, funktioniert setTheme nicht. Ich habe selbst keine Erfahrung mit Themen, aber zwei alternative Optionen, die ich mir vorstellen kann, sind:

  1. Rufen Sie stattdessen setTheme in onCreate () auf, oder
  2. redo setContentView (R.layout.mainscreen); um die Wiederherstellung des gesamten Layouts zu erzwingen.

Vielen Dank ! Das läuft in Ordnung, aber ich sehe nicht, was ich erwartet habe. Kurz bevor ich Ihren Code ausführe, führe ich Activity.setTheme (newtheme) aus, aber dieser Aufruf von invalidate () bewirkt nicht, dass sich das Thema ändert (z. B. von Dunkel zu Hell). Sollte invalidate () dazu in der Lage sein?
MickeyR

@MickeyR nein, sollte es nicht. Überprüfen Sie meine aktualisierte Antwort. Wenn diese beiden Optionen nicht funktionieren, müssen Sie Ihre Aktivität neu starten.
Aleadam

Option (1) funktioniert. Meine App startet mit dem richtigen Thema, aber wenn ich es während der Ausführung ändere, muss ich meine App neu starten, damit onCreate () erneut aufgerufen wird.
MickeyR

Option (2) ist der Weg, den ich nehmen wollte. Wenn das Thema während des Laufens geändert wird, wollte ich, dass onRestart () Folgendes tut: - setTheme (getPreferenceTheme ()); und setContentView (R.layout.main); Das ändert aber nichts an meinem Thema. Ich kann diese zweite Option nicht zum Laufen bringen ...?!
MickeyR

Ich habe verstanden, dass ich die Ansichtshierarchie erneut aufblasen muss, damit Option (2) funktioniert. Ich habe verschiedene Dinge versucht, um dies zu erreichen, bin mir aber nicht sicher, was dies bedeutet und wie ich das tun soll.
MickeyR

41

Versuchen getWindow().getDecorView().findViewById(android.R.id.content).invalidate();


3
Vielen Dank ! Gleiche Antwort, die ich oben an Aleadam gepostet habe. Diese Ungültigkeit () bewirkt nicht, dass das Aktivitätsthema aktualisiert wird, was ich brauche.
MickeyR

36

Wenn Sie recreate()es versuchen , wird diese Aktivität neu erstellt.


4
Ich habe alle Optionen in diesem Thread ausprobiert, und dies ist die einzige, die mit den am wenigsten unerwünschten Nebenwirkungen funktioniert hat.
Swooby

1
Was ist, wenn ich dies in der onResumeMethode tun muss . Dies gibt mir Endlosschleife: /
Kamil Witkowski

Nun, ich empfehle es nicht zu verwenden, bis Sie wirklich brauchen. Sie können ein Flag in den freigegebenen Einstellungen speichern, um die Endlosschleife zu vermeiden.
Mohanad ALKHOULI

Dies funktioniert, aber ich würde nicht empfehlen, es in der realen Produktionsmodus-App zu verwenden. Ich brauchte es nur für den Debug-Modus, daher ist der Nebeneffekt der gesamten Aktualisierung der Benutzeroberfläche nicht kritisch.
Drorsun

31

Lösung:

Leute, ich habe alle Ihre Lösungen ausprobiert, aber sie haben bei mir nicht funktioniert. Ich muss setVisibility von EditText auf VISIBLE setzen. Dieser EditText sollte dann in ScrollView sichtbar sein , aber ich konnte die Stammansicht nicht aktualisieren , um wirksam zu werden. Ich habe mein Problem gelöst, als ich die Ansicht aktualisieren musste, sodass ich die ScrollView-Sichtbarkeit in GONE geändert und sie dann erneut auf VISIBLE gesetzt habe, damit sie wirksam wird, und es hat bei mir funktioniert. Dies ist nicht die genaue Lösung, aber es hat nur funktioniert.

 private void refreshView(){
    mScrollView.setVisibility(View.GONE);
    mScrollView.setVisibility(View.VISIBLE);
}

2
@MickeyR Bitte akzeptieren Sie eine Antwort, damit die Leute die Lösung leicht finden können
Naveed Ahmad

wow .. Ich habe auch alle vorgeschlagenen Lösungen ausprobiert, aber dies scheint die einzige zu sein, die funktioniert, aber es ist irgendwie schrecklich ...
Rik van Velzen

Ich weiß nicht, warum @MickeyR diese Antwort nicht akzeptiert
Naveed Ahmad

1
@NaveedAhmad Danke! Nach 4 Stunden, in denen ich alles getan hatte, war dies die einzige Lösung, die funktionierte.
Codelicious

10

Das Aufrufen invalidate()oder postInvalidate()im Root-Layout garantiert anscheinend NICHT, dass untergeordnete Ansichten neu gezeichnet werden. In meinem speziellen Fall war mein Root-Layout ein TableLayout und hatte mehrere untergeordnete Elemente der Klassen TableRow und TextView. Der Aufruf postInvalidate(), oder requestLayout()oder sogar forceLayout()auf der Root - Objekt Tablelayout verursachte keine Textviews im Layout neu gezeichnet werden.

Am Ende habe ich das Layout rekursiv analysiert, nach diesen TextViews gesucht und dann postInvalidate()jedes dieser TextView-Objekte aufgerufen.

Der Code ist auf GitHub zu finden: https://github.com/jkincali/Android-LinearLayout-Parser


9

Ansonsten können Sie dies auch versuchen-

ViewGroup vg = (ViewGroup) findViewById (R.id.videoTitleTxtView);
 vg.removeAllViews();
 vg.refreshDrawableState();

4
Danke dafür ! Aber dies entfernte alle Ansichten, die ich hatte (TextView, Schaltflächen usw.), zeichnete sie aber nicht neu - mein Bildschirm blieb leer ...
MickeyR

Sie müssen Ihre Ansicht richtig aktualisieren und dann die Zeichenfunktion erneut aufrufen. nach dem Reinigen der vorherigen Ansicht.
Datta Kunde

4

Stellen Sie einfach Ihre Inhaltsansicht in onresume ein

setContentView (R.layout.yourview) in onResume ..

Beispiel:

@Override
public void onResume(){
super.onResume();
setContentView(R.layout.activity_main); 
postIncomeTotals();
}

Hallo, ich habe es versucht und die gleichen Daten in der Listenansicht werden zweimal abgerufen. Wenn ich also 4 Zeilen hatte und beim Aktualisieren eine fünfte Zeile hinzugefügt werden sollte, habe ich stattdessen 10, dann 15, ... was tun?
iOSAndroidWindowsMobileAppsDev

4

Versuchen Sie diese Problemumgehung für das Themenproblem:

@Override
public void onBackPressed() {
    NavUtils.navigateUpTo(this, new Intent(this,
            MyNeedToBeRefreshed.class));
}

3
Intent intent = getIntent();
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
finish();
startActivity(intent);

Auf diese Weise können Sie Themenänderungen neu laden und die Animationen ausblenden.


3

Ich hatte auch dieses Problem, aber nach Farhans Vorbild setContentView()tat ich genau das. Die Verwendung setContentView()allein reichte jedoch nicht aus. Ich stellte fest, dass ich alle meine Ansichten mit Informationen neu füllen musste. Um dies zu beheben, habe ich den gesamten Code auf eine andere Methode gezogen (ich habe ihn Build genannt) und in meiner onCreateMethode diesen Build einfach aufgerufen. Wenn nun mein Ereignis eintritt, dass meine Aktivität "aktualisiert" werden soll, rufe ich einfach build auf, gebe ihm die neuen Informationen (die ich als zu erstellende Parameter übergebe) und ich habe eine aktualisierte Aktivität.



0

Ich weiß nicht, ob das sicher ist oder nicht, aber es hat bei mir funktioniert. Ich bin selbst auf dieses Problem gestoßen und habe es versucht invalidate()und requestLayout()aber ohne Erfolg. Also habe ich einfach noch einmal angerufen onCreate(null)und es hat funktioniert. Wenn dies nicht sicher ist, lassen Sie es mich bitte wissen. Hoffe das hilft jemandem da draußen.


Sie setzen den savedInstanceState auf null, was zu unerwartetem Verhalten führen kann. Für weitere Informationen: stackoverflow.com/questions/15115975/…
PhilipB

0

So habe ich mein Layout aktualisiert

Intent intent = getIntent();
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION);
finish();
startActivity(intent);

0

Um eine Ansicht zu löschen, die ViewGroup erweitert, müssen Sie nur die Methode verwenden removeAllViews()

Einfach so (wenn Sie eine ViewGroup haben myElement):

myElement.removeAllViews()


-1

Ich bin mir nicht sicher, ob es ein guter Ansatz ist, aber ich rufe dies jedes Mal an:

setContentView(R.layout.mainscreen);

-8

Rufen Sie einfach die Aktivität selbst mit der Absicht erneut auf. Gehen Sie beispielsweise folgendermaßen vor, um das Layout von MainActivity zu aktualisieren:

startActivity(new Intent(MainActivity.this, MainActivity.class));

2
Das ist hässlich! Wenn Sie dies tun, fügen Sie einfach eine neue Aktivität zum Stapel hinzu. Wenn Sie also die Zurück-Taste drücken, kehren Sie zur gleichen Aktivität zurück.
Daniel Beltrami
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.