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);
}
MickeyR
quelle
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.
Aleadam
quelle
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();

Keyboard-Surfer
quelle
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.

Mohanad ALKHOULI
quelle
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);
}
Naveed Ahmad
quelle
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

jkincali
quelle
9

Ansonsten können Sie dies auch versuchen-

ViewGroup vg = (ViewGroup) findViewById (R.id.videoTitleTxtView);
 vg.removeAllViews();
 vg.refreshDrawableState();
Datta Kunde
quelle
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();
}
Farhan
quelle
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));
}
Krilivye
quelle
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.

Codeversiert
quelle
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.

user3612162
quelle
2

Dies scheint ein bekannter Fehler zu sein .

Ben Williams
quelle
setTheme funktioniert, wenn ich meine Aktivität neu starte (beende finish () und dann startActivity ()). Ich kann es einfach nicht dazu bringen, das Thema zu
aktualisieren,
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.

Cai
quelle
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);
sivaBE35
quelle
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()
Jack'
quelle
0

Versuche dies

view.requestLayout();
Milind Chaudhary
quelle
-1

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

setContentView(R.layout.mainscreen);
Krzysztof Tkacz
quelle
-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));
Anshul Aggarwal
quelle
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