Je demande des images au présentateur de l'adaptateur:
@Override
public void onBindViewHolder(SiteAdapter.ViewHolder holder, int position)
{
Site site = sites.get(position);
holder.siteName.setText(site.getName());
requestHolderLogo(holder, site.getLinks().getLogoUrl());
}
private void requestHolderLogo(final ViewHolder holder, final String logoUrl)
{
compositeSubscription.add(
presenter.bitmap(logoUrl)
.subscribe(
bitmap -> {
holder.siteLogo.setImageBitmap(bitmap);
holder.siteLogo.setVisibility(View.VISIBLE);
},
error -> {
holder.siteName.setVisibility(View.VISIBLE);
})
);
}
Je devrais me désabonner lorsque ViewHolder
sera réutilisé. C'est facile.
Mais comment arrêter tout abonnement lorsque la vue est détruite? Je devrais aussi probablement annuler la référence du présentateur pour éviter une fuite de mémoire
Je pense que la meilleure façon de le faire serait de:
subscription
dans le SiteAdapter.ViewHolder
unsubscribe
l'objet subscription
dans onBindViewHolder
(il est appelé lorsque ViewHolder
est réutilisé)CompositeSubscription
dans votre adapter
onDetachedFromRecyclerView
de votre Adapter
à unsubscribe
le compositeSubscription
Ainsi:
public class SiteAdapter extends RecyclerView.Adapter<SiteAdapter.ViewHolder> {
private CompositeSubscription compositeSubscription = new CompositeSubscription();
// other needed SiteAdapter methods
@Override
public void onBindViewHolder(SiteAdapter.ViewHolder holder, int position) {
if (holder.subscription != null && !holder.subscription.isUnsubscribed()) {
compositeSubscription.remove(holder.subscription);
// this will unsubscribe the subscription as well
}
Site site = sites.get(position);
holder.siteName.setText(site.getName());
requestHolderLogo(holder, site.getLinks().getLogoUrl());
}
private void requestHolderLogo(final SiteAdapter.ViewHolder holder, final String logoUrl) {
holder.subscription = presenter.bitmap(logoUrl)
.subscribe(
bitmap -> {
holder.siteLogo.setImageBitmap(bitmap);
holder.siteLogo.setVisibility(View.VISIBLE);
},
error -> {
holder.siteName.setVisibility(View.VISIBLE);
});
compositeSubscription.add(holder.subscription);
}
@Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
compositeSubscription.unsubscribe();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public Subscription subscription;
// some holder-related stuff
public ViewHolder(View itemView) {
super(itemView);
// init holder
}
}
}
Pour les autres qui ont le même problème: viewDetachedFromWindow dans l'adaptateur est appelé uniquement lorsque l'adaptateur est défini sur null dans onPause (Activity, Fragment) ou onDetachFromWindow (Activity, Fragment).
recyclerview.setAdapter (null)
Ensuite, vous obtenez viewDetachedFromWindow (...) où vous pouvez publier vos états internes et vos abonnements. Je configurerais vos abonnements dans une liaison, assurez-vous que tous les abonnements réappliquent avant chaque appel de liaison, car une vue peut être recyclée.
Une autre possibilité consiste à gonfler une vue personnalisée au lieu d'une seule disposition dans votre usine. Ensuite, vous pouvez effectuer le nettoyage dans la vue personnalisée onDetachFromWindow (). Vous obtenez également onDetachedFromWindow sans définir l'adaptateur sur null.