Jak wymusić odświeżenie całego widoku układu?

173

Chcę wymusić ponowne rysowanie / odświeżanie głównego widoku zasobów układu, na przykład metody Activity.onResume (). W jaki sposób mogę to zrobić ?

Przez główny widok układu mam na myśli ten („R.layout.mainscreen” poniżej), który jest wywoływany w moim Activity.onCreate (), na przykład: -

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.mainscreen);
}
MickeyR
źródło
Czy próbowałeś nazwać otaczający ją Linear / Relative / WhatersLayout, wywołać na nim findViewById, a następnie wywołać na nim invalidate ()? (Powiedziałbym to jako odpowiedź, ale nie wiem, czy unieważnienie rodziców również unieważnia dzieci i nie jestem gdzieś, w którym mógłbym to sprawdzić.)
Ben Williams
Dziękuję również ! Nadal jednak z tym walczę. Czy możesz spojrzeć na to, co zamieściłem poniżej. Potrzebuję tego kodu (lub innego?), Aby spowodować odświeżenie mojego motywu ...
MickeyR

Odpowiedzi:

149

Aby ściśle odpowiedzieć na pytanie: Użyj unieważnienia ():

public void invalidate () Od: API poziom 1

Unieważnij cały widok. Jeśli widok jest widoczny, w przyszłości zostanie wywołane onDraw (Canvas). To musi być wywołane z wątku interfejsu użytkownika. Aby wywołać z wątku spoza interfejsu użytkownika, wywołaj postInvalidate ().

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

Teraz, gdy działanie zostanie wznowione, każdy widok sam się narysuje. Nie powinno być potrzebne wywołanie unieważnienia (). Aby zastosować motyw, upewnij się, że robisz to przed narysowaniem jakiegokolwiek widoku, tj. PrzedsetContentView(R.layout.mainscreen);

public void setTheme (int Resid) Od: API Poziom 1

Ustaw motyw podstawowy dla tego kontekstu. Należy zauważyć, że należy to wywołać przed utworzeniem wystąpienia jakichkolwiek widoków w Context (na przykład przed wywołaniem setContentView (View) lub inflate (int, ViewGroup)).

Dokumentacja dotycząca interfejsu API znajduje się tutaj: http://developer.android.com/reference/android/view/ContextThemeWrapper.html#setTheme%28int%29

Ponieważ metoda onDraw () działa na już utworzonych widokach, setTheme nie będzie działać. Sam nie mam doświadczenia z motywami, ale myślę, że dwie alternatywne opcje to:

  1. zamiast tego wywołaj setTheme w onCreate () lub
  2. ponów setContentView (R.layout.mainscreen); wymusić przywrócenie całego układu.
Aleadam
źródło
Dzięki ! Działa dobrze, ale nie widzę, czego się spodziewałem. Tuż przed uruchomieniem twojego kodu uruchamiam Activity.setTheme (newtheme), ale to wywołanie invalidate () nie powoduje zmiany motywu (np. Z Dark na Light). Czy invalidate () powinno móc to zrobić?
MickeyR
@MickeyR nie, nie powinno. Sprawdź moją zaktualizowaną odpowiedź. Jeśli te dwie opcje nie zadziałają, konieczne będzie ponowne uruchomienie działania.
Aleadam
Opcja (1) działa. Moja aplikacja uruchomi się z poprawnym motywem, ale jeśli zmienię go podczas działania, muszę ponownie uruchomić aplikację, aby ponownie wywołać onCreate ().
MickeyR
Opcja (2) to trasa, którą chciałem wybrać. Tak więc, gdy motyw zostanie zmieniony podczas działania, chciałem, aby onRestart () zrobił to: - setTheme (getPreferenceTheme ()); i setContentView (R.layout.main); Ale to nie zmienia mojego motywu. Nie mogę uruchomić tej drugiej opcji ...?!
MickeyR
Zrozumiałem, że aby opcja (2) działała, muszę „ponownie wypełnić hierarchię widoków”. Próbowałem różnych rzeczy, aby to osiągnąć, ale nie jestem pewien, co to oznacza ani jak to zrobić.
MickeyR
41

Próbować getWindow().getDecorView().findViewById(android.R.id.content).invalidate();

klawiszowiec
źródło
3
Dzięki ! Ta sama odpowiedź, którą zamieściłem powyżej dla Aleadam. To unieważnienie () nie powoduje odświeżenia motywu działania, czego potrzebuję.
MickeyR
36

Wypróbuj recreate()to spowoduje odtworzenie tego działania.

Mohanad ALKHOULI
źródło
4
Wypróbowałem wszystkie opcje w tym wątku i jest to jedyna, która działała z najmniej niepożądanymi efektami ubocznymi.
swooby
1
Co jeśli potrzebuję tego w onResumemetodzie. To daje mi nieskończoną pętlę: /
Kamil Witkowski
Cóż, nie polecam go używać, dopóki naprawdę nie potrzebujesz. Możesz zapisać niektóre flagi we wspólnych preferencjach, aby uniknąć nieskończonej pętli.
Mohanad ALKHOULI
to działa, ale nie polecam używania go w aplikacji w trybie produkcyjnym. Potrzebowałem go tylko do trybu debugowania, więc efekt uboczny odświeżania całego interfejsu użytkownika nie jest krytyczny.
drorsun
31

Rozwiązanie:

Chłopaki, wypróbowałem wszystkie Twoje rozwiązania, ale nie zadziałały, muszę ustawić setVisibility of EditText na VISIBLE i ten EditText powinien być wtedy widoczny w ScrollView , ale nie mogłem odświeżyć widoku głównego, aby odniosło skutek. Rozwiązałem problem, kiedy muszę odświeżyć widok, więc zmieniłem widoczność ScrollView na GONE, a następnie ponownie ustawiłem ją na VISIBLE, aby odniosła skutek i zadziałało. To nie jest dokładne rozwiązanie, ale tylko działało.

 private void refreshView(){
    mScrollView.setVisibility(View.GONE);
    mScrollView.setVisibility(View.VISIBLE);
}
Naveed Ahmad
źródło
2
@MickeyR Proszę, zaakceptuj odpowiedź, aby ludzie mogli łatwo znaleźć rozwiązanie
Naveed Ahmad
wow .. Wypróbowałem też wszystkie proponowane rozwiązania, ale wydaje się, że jedyne działające, ale to trochę okropne ...
Rik van Velzen
Nie wiem, dlaczego @MickeyR nie akceptuje tej odpowiedzi
Naveed Ahmad
1
@NaveedAhmad Dziękuję! Po 4 godzinach robienia wszystkiego, co mogłem, było to jedyne rozwiązanie, które zadziałało.
Codelicious
10

Wywołanie invalidate()lub postInvalidate()w układzie głównym najwyraźniej NIE gwarantuje, że widoki potomne zostaną przerysowane. W moim konkretnym przypadku moim układem głównym był TableLayout i miał kilka elementów podrzędnych klasy TableRow i TextView. Wywołanie postInvalidate(), a requestLayout()nawet forceLayout()w głównym obiekcie TableLayout, nie spowodowało ponownego narysowania żadnych TextViews w układzie.

W końcu to, co zrobiłem, to rekurencyjne analizowanie układu w poszukiwaniu tych TextViews, a następnie wywoływanie postInvalidate()każdego z tych obiektów TextView.

Kod można znaleźć na GitHub: https://github.com/jkincali/Android-LinearLayout-Parser

jkincali
źródło
9

W przeciwnym razie możesz spróbować również tego -

ViewGroup vg = (ViewGroup) findViewById (R.id.videoTitleTxtView);
 vg.removeAllViews();
 vg.refreshDrawableState();
Datta Kunde
źródło
4
Dzięki za to ! Ale to usunęło wszystkie widoki, które miałem (TextView, przyciski itp.), Ale nie narysowałem ich ponownie - mój ekran pozostał pusty ...
MickeyR
musisz odpowiednio odświeżyć widok, a następnie ponownie wywołać funkcję rysowania. po wyczyszczeniu poprzedniego widoku.
Datta Kunde
4

Po prostu ustaw widok treści w trybie onresume

setContentView (R.layout.yourview) wewnątrz onResume ..

Przykład:

@Override
public void onResume(){
super.onResume();
setContentView(R.layout.activity_main); 
postIncomeTotals();
}
Farhan
źródło
Cześć, próbowałem tego i te same dane w widoku listy są pobierane dwukrotnie, stąd gdybym miał 4 wiersze i odświeżanie miało dodać piąty wiersz, zamiast tego skończyło się na 10, potem 15, ... co t zrobić?
iOSAndroidWindowsMobileAppsDev
4

Wypróbuj to obejście problemu z motywami:

@Override
public void onBackPressed() {
    NavUtils.navigateUpTo(this, new Intent(this,
            MyNeedToBeRefreshed.class));
}
Krilivye
źródło
3
Intent intent = getIntent();
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
finish();
startActivity(intent);

Pozwala to na ponowne załadowanie ze zmianami motywu i ukrycie animacji.

Codeversed
źródło
3

Miałem również ten problem, ale podążając za przykładem Farhana dotyczącym używania setContentView(), zrobiłem to. setContentView()Samo używanie nie wystarczyło. Stwierdziłem, że muszę ponownie wypełnić wszystkie swoje poglądy informacjami. Aby to naprawić, po prostu wyciągnąłem cały kod do innej metody (nazwałem to budowaniem), aw mojej onCreatemetodzie po prostu wywołuję tę kompilację. Teraz za każdym razem, gdy pojawia się moje zdarzenie, w którym chcę, aby moja aktywność się „odświeżyła”, po prostu wywołuję build, podaję nowe informacje (które przekazuję jako parametry do zbudowania) i mam odświeżoną aktywność.

user3612162
źródło
2

Wygląda na to, że jest to znany błąd .

Ben Williams
źródło
setTheme działa znaleźć, kiedy ponownie uruchomię moją aktywność (wywołanie finish (), a następnie startActivity ()). Po prostu nie mogę odświeżyć motywu bez ponownego uruchomienia mojej aktywności ...
MickeyR
0

Nie wiem, czy to jest bezpieczne, czy nie, ale zadziałało. Jakbym wpadł na ten problem i sam spróbował invalidate()i requestLayout()ale bezskutecznie. Więc po prostu ponownie zadzwoniłem onCreate(null)i zadziałało. Jeśli jest to niebezpieczne, daj mi znać. Mam nadzieję, że to komuś pomoże.

Cai
źródło
Ustawiasz wartość saveInstanceState na wartość null, co może spowodować nieoczekiwane zachowanie. Więcej informacji: stackoverflow.com/questions/15115975/…
PhilipB
0

W ten sposób odświeżyłem mój układ

Intent intent = getIntent();
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION);
finish();
startActivity(intent);
sivaBE35
źródło
0

Aby wyczyścić widok rozszerzający ViewGroup, wystarczy użyć metody removeAllViews()

Tak po prostu (jeśli masz nazwę ViewGroup myElement):

myElement.removeAllViews()
Jacek'
źródło
0

Spróbuj tego

view.requestLayout();
Milind Chaudhary
źródło
-1

Nie jestem pewien, czy to dobre podejście, ale za każdym razem dzwonię do tego:

setContentView(R.layout.mainscreen);
Krzysztof Tkacz
źródło
-8

Po prostu wywołaj działanie ponownie, używając intencji. Na przykład, aby odświeżyć układ MainActivity, wykonaj następujące czynności:

startActivity(new Intent(MainActivity.this, MainActivity.class));
Anshul Aggarwal
źródło
2
To brzydkie! Kiedy to robisz, po prostu dodajesz nową aktywność na stosie, więc po naciśnięciu przycisku Wstecz wrócisz do tej samej czynności.
Daniel Beltrami