J'ai un RecyclerView qui charge certaines données de l'API, comprend une URL d'image et certaines données, et j'utilise networkImageView pour charger l'image paresseux.
@Override
public void onResponse(List<Item> response) {
mItems.clear();
for (Item item : response) {
mItems.add(item);
}
mAdapter.notifyDataSetChanged();
mSwipeRefreshLayout.setRefreshing(false);
}
Voici l'implémentation pour Adapter:
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());
}
Le problème, c’est que lorsque nous avons actualisé le recyclerView, il clignote pendant un très court instant au début, ce qui semble étrange.
Je viens d'utiliser GridView/ListView à la place et cela a fonctionné comme je m'y attendais. Il n'y avait pas de blincking.
configuration pour RecycleView dans 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);
Quelqu'un est confronté à un tel problème? Quelle pourrait être la raison?
Essayez d’utiliser des identifiants stables dans votre RecyclerView.Adapter
setHasStableIds(true)
et remplace getItemId(int position)
.
Sans ID stable, après notifyDataSetChanged()
, les ViewHolders ne sont généralement pas affectés aux mêmes positions. C'était la raison de cligner des yeux dans mon cas.
Vous pouvez trouver un bonne explication ici.
Selon cette numéro page .... c'est l'animation de changement d'élément de recycleview par défaut ... Vous pouvez le désactiver .. essayez ceci
recyclerView.getItemAnimator().setSupportsChangeAnimations(false);
Changement dans la dernière version
Cité de blog de développeur Android :
Notez que cette nouvelle API n'est pas compatible avec les versions antérieures. Si vous avez précédemment implémenté un ItemAnimator, vous pouvez plutôt étendre SimpleItemAnimator, qui fournit l'ancienne API en encapsulant la nouvelle API. Vous remarquerez également que certaines méthodes ont été entièrement supprimées de ItemAnimator. Par exemple, si vous appeliez recyclerView.getItemAnimator (). SetSupportsChangeAnimations (false), ce code ne sera plus compilé. Vous pouvez le remplacer par:
ItemAnimator animator = recyclerView.getItemAnimator(); if (animator instanceof SimpleItemAnimator) { ((SimpleItemAnimator) animator).setSupportsChangeAnimations(false); }
Cela a simplement fonctionné:
recyclerView.getItemAnimator().setChangeDuration(0);
J'ai le même problème de chargement d'image à partir de certaines URL, puis imageView clignote. Résolu en utilisant
notifyItemRangeInserted()
au lieu de
notifyDataSetChanged()
ce qui évite de recharger ces anciennes données inchangées.
essayez ceci pour désactiver l'animation par défaut
ItemAnimator animator = recyclerView.getItemAnimator();
if (animator instanceof SimpleItemAnimator) {
((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
}
c'est la nouvelle façon de désactiver l'animation depuis Android support 23
cette ancienne méthode fonctionnera pour l'ancienne version de la bibliothèque de support
recyclerView.getItemAnimator().setSupportsChangeAnimations(false)
En supposant que mItems
soit la collection qui sauvegarde votre Adapter
, pourquoi supprimez-vous tout et rajoutez-vous? En gros, vous lui dites que tout a changé. Ainsi, RecyclerView lie à nouveau toutes les vues, car je suppose que la bibliothèque d’images ne la gère pas correctement, même si elle réinitialise la vue, même s’il s’agit de la même adresse URL. Peut-être qu'ils avaient une solution intégrée pour AdapterView afin que cela fonctionne correctement dans GridView.
Au lieu d'appeler notifyDataSetChanged
, ce qui entraînera la liaison de toutes les vues, appelez des événements de notification granulaires (notification ajoutée/supprimée/déplacée/mise à jour) afin que RecyclerView ne lie à nouveau que les vues nécessaires et que rien ne scintille.
Recyclerview utilise DefaultItemAnimator comme animateur par défaut. Comme vous pouvez le voir dans le code ci-dessous, ils modifient l'alpha du détenteur de la vue lors du changement d'élément:
@Override
public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) {
...
final float prevAlpha = ViewCompat.getAlpha(oldHolder.itemView);
...
ViewCompat.setAlpha(oldHolder.itemView, prevAlpha);
if (newHolder != null) {
....
ViewCompat.setAlpha(newHolder.itemView, 0);
}
...
return true;
}
Je voulais conserver le reste des animations, mais supprimer le "scintillement". J'ai donc cloné DefaultItemAnimator et supprimé les 3 lignes alpha ci-dessus.
Pour utiliser le nouvel animateur, appelez simplement setItemAnimator () sur votre RecyclerView:
mRecyclerView.setItemAnimator(new MyItemAnimator());
Essayez d'utiliser la propriété stableId dans la vue Recycler. L'article suivant l'explique brièvement
Hey @ ALi, il pourrait être tard en replay. J'ai également fait face à ce problème et résolu avec la solution ci-dessous, il peut vous aider s'il vous plaît vérifier.
LruBitmapCache.Java la classe est créée pour obtenir la taille du cache d'images
import Android.graphics.Bitmap;
import Android.support.v4.util.LruCache;
import com.Android.volley.toolbox.ImageLoader.ImageCache;
public class LruBitmapCache extends LruCache<String, Bitmap> implements
ImageCache {
public static int getDefaultLruCacheSize() {
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
final int cacheSize = maxMemory / 8;
return cacheSize;
}
public LruBitmapCache() {
this(getDefaultLruCacheSize());
}
public LruBitmapCache(int sizeInKiloBytes) {
super(sizeInKiloBytes);
}
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight() / 1024;
}
@Override
public Bitmap getBitmap(String url) {
return get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
put(url, bitmap);
}
}
VolleyClient.Java classe singleton [extension de l'application] ajoutée sous le code
dans le constructeur de classe singleton VolleyClient, ajoutez le fragment ci-dessous pour initialiser ImageLoader.
private VolleyClient(Context context)
{
mCtx = context;
mRequestQueue = getRequestQueue();
mImageLoader = new ImageLoader(mRequestQueue,getLruBitmapCache());
}
J'ai créé la méthode getLruBitmapCache () pour renvoyer LruBitmapCache
public LruBitmapCache getLruBitmapCache() {
if (mLruBitmapCache == null)
mLruBitmapCache = new LruBitmapCache();
return this.mLruBitmapCache;
}
J'espère que ça va vous aider.
Dans Kotlin, vous pouvez utiliser "extension de classe" pour RecyclerView:
fun RecyclerView.disableItemAnimator() {
(itemAnimator as? SimpleItemAnimator)?.supportsChangeAnimations = false
}
// sample of using in Activity:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
myRecyclerView.disableItemAnimator()
// ...
}
L'utilisation de méthodes de recyclage appropriées pour mettre à jour les vues résoudra ce problème
Tout d'abord, apportez des modifications à la liste
mList.add(item);
or mList.addAll(itemList);
or mList.remove(index);
Puis notifiez en utilisant
notifyItemInserted(addedItemIndex);
or
notifyItemRemoved(removedItemIndex);
or
notifyItemRangeChanged(fromIndex, newUpdatedItemCount);
J'espère que ça va aider !!
pour moi recyclerView.setHasFixedSize(true);
travaillé
pour mon application, certaines données ont été modifiées, mais je ne voulais pas que la vue entière clignote.
Je l'ai résolu en atténuant uniquement oldview avec une valeur inférieure à 0,5 alpha et en démarrant l'option newview alpha à 0,5. Cela a créé une transition plus atténuée sans faire disparaître complètement la vue.
Malheureusement, à cause d'implémentations privées, je ne pouvais pas sous-classer le DefaultItemAnimator afin d'effectuer cette modification. J'ai donc dû cloner le code et apporter les modifications suivantes.
dans animateChange:
ViewCompat.setAlpha(newHolder.itemView, 0); //change 0 to 0.5f
dans animateChangeImpl:
oldViewAnim.alpha(0).setListener(new VpaListenerAdapter() { //change 0 to 0.5f
J'ai eu un problème similaire et cela a fonctionné pour moi Vous pouvez appeler cette méthode pour définir la taille du cache d'images
private int getCacheSize(Context context) {
final DisplayMetrics displayMetrics = context.getResources().
getDisplayMetrics();
final int screenWidth = displayMetrics.widthPixels;
final int screenHeight = displayMetrics.heightPixels;
// 4 bytes per pixel
final int screenBytes = screenWidth * screenHeight * 4;
return screenBytes * 3;
}