Mam RecyclerView, który ładuje niektóre dane z API, zawiera adres URL obrazu i niektóre dane, i używam networkImageView do leniwego ładowania obrazu.
@Override
public void onResponse(List<Item> response) {
mItems.clear();
for (Item item : response) {
mItems.add(item);
}
mAdapter.notifyDataSetChanged();
mSwipeRefreshLayout.setRefreshing(false);
}
Oto implementacja dla adaptera:
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int position) {
if (isHeader(position)) {
return;
}
// - get element from your dataset at this position
// - replace the contents of the view with that element
MyViewHolder holder = (MyViewHolder) viewHolder;
final Item item = mItems.get(position - 1); // Subtract 1 for header
holder.title.setText(item.getTitle());
holder.image.setImageUrl(item.getImg_url(), VolleyClient.getInstance(mCtx).getImageLoader());
holder.image.setErrorImageResId(android.R.drawable.ic_dialog_alert);
holder.origin.setText(item.getOrigin());
}
Problem polega na tym, że gdy mamy odświeżenie w RecyklerView, na początku świeci przez bardzo krótki czas, co wygląda dziwnie.
Zamiast tego użyłem GridView / ListView i działało zgodnie z oczekiwaniami. Nie było mrugnięcia okiem.
konfiguracja RecycleView w onViewCreated of my Fragment
:
mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
mRecyclerView.setHasFixedSize(true);
mGridLayoutManager = (GridLayoutManager) mRecyclerView.getLayoutManager();
mGridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
return mAdapter.isHeader(position) ? mGridLayoutManager.getSpanCount() : 1;
}
});
mRecyclerView.setAdapter(mAdapter);
Czy ktoś miał taki problem? jaki może być powód?
Odpowiedzi:
Spróbuj użyć stabilnych identyfikatorów w swoim RecyclerView.Adapter
setHasStableIds(true)
i zastąpgetItemId(int position)
.Bez stabilnych identyfikatorów, po
notifyDataSetChanged()
ViewHolders zwykle przypisane do różnych pozycji. To był powód mrugania w moim przypadku.Tutaj znajdziesz dobre wyjaśnienie.
źródło
Zgodnie z tą stroną wydania … jest to domyślna animacja zmiany przedmiotu z recyklingu… Możesz ją wyłączyć… spróbuj tego
Zmiana w najnowszej wersji
Cytat z bloga programistów Androida :
źródło
To po prostu zadziałało:
źródło
code
ItemAnimator animator = recyclingView.getItemAnimator (); if (instancja animatora SimpleItemAnimator) {((SimpleItemAnimator) animator) .setSupportsChangeAnimations (false); }code
Mam ten sam problem z ładowaniem obrazu z niektórych adresów URL, a następnie miga imageView. Rozwiązany za pomocą
zamiast
co pozwala uniknąć ponownego załadowania tych niezmienionych starych danych.
źródło
spróbuj tego, aby wyłączyć domyślną animację
To nowy sposób na wyłączenie animacji od czasu obsługi Androida 23
ten stary sposób zadziała dla starszej wersji biblioteki obsługi
źródło
Zakładając, że
mItems
jest to kolekcja, która wspiera TwojąAdapter
, dlaczego usuwasz wszystko i ponownie dodajesz? Zasadniczo mówisz mu, że wszystko się zmieniło, więc RecyclerView ponownie wiąże wszystkie widoki, niż zakładam, że biblioteka obrazów nie obsługuje go poprawnie, gdy nadal resetuje widok, mimo że jest to ten sam adres URL obrazu. Może przygotowali jakieś rozwiązanie dla AdapterView, aby działało dobrze w GridView.Zamiast wywoływać,
notifyDataSetChanged
co spowoduje ponowne powiązanie wszystkich widoków, wywołaj szczegółowe zdarzenia powiadomień (powiadomienie dodane / usunięte / przeniesione / zaktualizowane), aby RecyclerView ponownie powiązał tylko niezbędne widoki i nic nie będzie migotać.źródło
Recyclerview używa DefaultItemAnimator jako domyślnego animatora. Jak widać z poniższego kodu, zmieniają one alfa posiadacza widoku po zmianie przedmiotu:
Chciałem zachować resztę animacji, ale usunąć „migotanie”, więc sklonowałem DefaultItemAnimator i usunąłem powyższe 3 linie alfa.
Aby użyć nowego animatora, po prostu wywołaj setItemAnimator () w swoim RecyclerView:
źródło
W Kotlinie możesz użyć `` rozszerzenia klasy '' dla RecyclerView:
źródło
Hej @Ali, może być późna powtórka. Również napotkałem ten problem i rozwiązałem za pomocą poniższego rozwiązania, może pomóc ci to sprawdzić.
Klasa LruBitmapCache.java jest tworzona w celu pobrania rozmiaru pamięci podręcznej obrazu
Klasa singleton VolleyClient.java [rozszerza aplikację] dodana poniżej kodu
w konstruktorze klasy singleton VolleyClient dodaj poniższy fragment kodu, aby zainicjować ImageLoader
Utworzyłem metodę getLruBitmapCache (), aby zwracała LruBitmapCache
Mam nadzieję, że ci to pomoże.
źródło
dla mnie
recyclerView.setHasFixedSize(true);
pracowałźródło
W moim przypadku żadne z powyższych ani odpowiedzi z innych pytań dotyczących stackoverflow, które mają te same problemy, nie zadziałały.
Cóż, korzystałem z niestandardowej animacji za każdym razem, gdy element został kliknięty, dla którego wywoływałem notifyItemChanged (pozycja int, Object Payload), aby przekazać ładunek do mojej klasy CustomAnimator.
Zauważ, że w adapterze RecyclerView dostępne są 2 metody onBindViewHolder (...). Metoda onBindViewHolder (...) mająca 3 parametry będzie zawsze wywoływana przed metodą onBindViewHolder (...) mającą 2 parametry.
Generalnie zawsze nadpisujemy metodę onBindViewHolder (...) mającą 2 parametry, a głównym źródłem problemu było to, że robiłem to samo, ponieważ za każdym razem, gdy wywoływana jest funkcja notifyItemChanged (...), nasza metoda onBindViewHolder (...) być wywołane, w którym ładowałem mój obraz w ImageView za pomocą Picassa i to był powód, dla którego ładował się ponownie, niezależnie od tego, czy pochodzi z pamięci, czy z Internetu. Aż do załadowania pokazywał mi obraz zastępczy, który był powodem migania przez 1 sekundę za każdym razem, gdy klikałem widok przedmiotu.
Później nadpisuję też inną metodę onBindViewHolder (...) mającą 3 parametry. Tutaj sprawdzam, czy lista ładunków jest pusta, następnie zwracam implementację superklasy tej metody, w przeciwnym razie, jeśli są ładunki, ustawiam tylko wartość alfa posiadacza itemView na 1.
I tak, znalazłem rozwiązanie mojego problemu po niestety zmarnowaniu jednego pełnego dnia!
Oto mój kod dla metod onBindViewHolder (...):
onBindViewHolder (...) z 2 parametrami:
onBindViewHolder (...) z 3 parametrami:
Oto kod metody, którą wywołałem w onClickListener elementu viewHolder itemView w onCreateViewHolder (...):
Uwaga: Możesz uzyskać tę pozycję, wywołując metodę getAdapterPosition () elementu viewHolder z onCreateViewHolder (...).
Zastąpiłem również metodę getItemId (pozycja int) w następujący sposób:
i zadzwonił
setHasStableIds(true);
mój obiekt adaptera w działaniu.Mam nadzieję, że to pomoże, jeśli żadna z powyższych odpowiedzi nie zadziała!
źródło
W moim przypadku był znacznie prostszy problem, ale może wyglądać / odczuwać bardzo podobnie do powyższego problemu. Przekonwertowałem ExpandableListView na RecylerView z Groupie (używając funkcji ExpandableGroup Groupie). Mój początkowy układ miał następującą sekcję:
Gdy layout_height ustawiono na „wrap_content”, animacja z grupy rozwiniętej do grupy zwiniętej wyglądała tak, jakby migała, ale tak naprawdę była to po prostu animacja z „niewłaściwej” pozycji (nawet po wypróbowaniu większości zaleceń w tym wątku).
W każdym razie zwykła zmiana layout_height na match_parent w ten sposób rozwiązała problem.
źródło
Miałem podobny problem i to zadziałało dla mnie Możesz wywołać tę metodę, aby ustawić rozmiar pamięci podręcznej obrazu
źródło
w przypadku mojej aplikacji niektóre dane uległy zmianie, ale nie chciałem, aby cały widok migał.
Rozwiązałem to tylko wygaszając alfa oldview w dół o 0,5 alfa i uruchamiając alfa newview na 0,5. Stworzyło to łagodniejsze przejście bez całkowitego znikania widoku.
Niestety z powodu prywatnych implementacji nie mogłem wykonać podklasy DefaultItemAnimator w celu wprowadzenia tej zmiany, więc musiałem sklonować kod i wprowadzić następujące zmiany
w animateChange:
w animateChangeImpl:
źródło
Użycie odpowiednich metod podglądu recyklingu do aktualizacji widoków rozwiąże ten problem
Najpierw wprowadź zmiany na liście
Następnie powiadom za pomocą
Mam nadzieję, że to pomoże !!
źródło
Spróbuj użyć stabilnego identyfikatora w widoku recyklera. Poniższy artykuł krótko to wyjaśnia
https://medium.com/@hanru.yeh/recyclerviews-views-are-blinking-when-notifydatasetchanged-c7b76d5149a2
źródło
Rozwiązanie Kotlin:
źródło