2012-05-18 9 views
26

Moja odpowiedź na this question została właśnie zaakceptowana, ale zacząłem zastanawiać się, kiedy dokładnie trzeba unieważnić() widok, a kiedy nie jest to konieczne?Kiedy konieczne jest wykonanie metody invalidate() w widoku?

Po nieco myślenia doszedłem do wniosku, że to powinien pracy mniej więcej tak:

  • rzeczywisty rysunek „wszystkiego” występuje po onResume()
  • w „wolnych” części czasowych ekran może być przerysowana, ale tylko te, które były invalidated (wszystko pod spodem)

Dlatego wydaje się, gdybym coś zmienić po onResume() (np. w odpowiedzi na kliknięcie przycisku, powinienem invalidate() zmieniony View).

Jednak z tego, co mówi scana w this question, musi być bardziej złożona i zależy od tego, jakiej metody używa.

E.g. od tego, czy ktoś używa

lastClicked.setImageBitmap(); 

lub

lastClicked.setImageResource(); 

Więc, kiedy jest to konieczne do wykonania invalidate() na widoku i jak to naprawdę działa?

Odpowiedz

13

Zwykle system automatycznie zmienia rozmiar, ukrywanie, pokazywanie i wiele innych rzeczy dla widgetów, czasami ma problemy, jeśli bufor bazowy dla narysowanych pikseli lub danych kopii zapasowej zmienił się lub jest nieaktualny (zamieniasz zasób obrazu na widok lub zmiany surowych zbiorów danych). Dzieje się tak, ponieważ nie ma sposobu, aby system operacyjny mógł wiedzieć, że dane zmieniły się w określony sposób.

W tych przypadkach, gdy masz do czynienia z rysowaniem, musisz powiedzieć systemowi, że jego podstawowe dane nie są w dobrym stanie z Widget.invalidate(), a ponowne rysowanie zostanie umieszczone w kolejce w głównym wątku jak wspomniałeś.W zależności od implementacji systemu i wersji systemu Android, śledzenie zmian w systemie jest różne, ale normalnie zakładam, że zasoby systemowe (tablice bajtów, tablice znaków, indeksy zasobów, ręczne rysowanie w kontekście) nie są śledzone i muszą być unieważnij, a wszystko inne będzie obsługiwane przez system.

+0

Niektóre poprawia zdania, ale błędne podejście. !! -1 – ncm

54

(należy rozważyć przyjmowanie kilka odpowiedzi)

Generalnie invalidate() środki „przerysować na ekranie” i wyniki na wywołanie widoku za onDraw() metody. Jeśli więc coś się zmieni i musi zostać odzwierciedlone na ekranie, musisz zadzwonić pod numer invalidate(). Jednak w przypadku wbudowanych widżetów rzadko, o ile w ogóle, musisz wywoływać to samodzielnie. Gdy zmienisz stan widżetu, kod wewnętrzny zadzwoni pod numer invalidate(), a twoja zmiana zostanie odzwierciedlona na ekranie. Na przykład, jeśli zadzwonisz pod numer TextView.setText(), po wykonaniu dużego wewnętrznego przetwarzania (czy tekst pasuje do ekranu, czy trzeba go elipsować itp.), TextView wywoła invalidate(), zanim powróci setText(). Podobnie dla innych widżetów.

Jeśli zaimplementujesz niestandardowy widok, będziesz musiał zadzwonić pod numer invalidate(), gdy tylko zmieni się model podkładu i będziesz musiał przerysować swój widok. Może być również używany do tworzenia prostych animacji, w których można zmienić stan, a następnie zadzwonić pod numer invalidate(), zmienić stan ponownie, itp.

+1

Aby ukończyć tę odpowiedź, powiedziałbym, że wiele razy jest ważne, aby sprawdzić kod różnych metod, których można użyć w widgecie, aby zrozumieć, kiedy jest nieprawidłowe połączenie i zaimplementować układ, aby zminimalizować je. na przykład, jeśli masz złożony układ, pojedynczy tekst z wrap_content zawsze będzie invalide() cały układ na końcu każdego wywołania setText(), z drugiej strony, jeśli uda ci się uzyskać stały wymiar tylko tekstu wewnątrz widok zostanie zmieniony z powodu znacznie bardziej płynnego GUI. –

0

Należy pamiętać, że rysowanie na ekranie jest częstym procesem, za każdym razem, gdy aktualizujesz widok, ta zmiana powinna być propogowana i przerysowana, aby powiadomić o takiej zmianie. invalidate() to metoda wyzwalacza, która sygnalizuje wymuszenie ponownego wyszukuwania dowolnego widoku, dla którego chcesz wyświetlić zmiany.