I'm requesting images from presenter in adapter:
我正在从适配器中的演示者请求图像:
@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);
})
);
}
I should unsubscribe when ViewHolder
is re-used. It is easy.
我应该在重新使用ViewHolder时取消订阅。这很容易。
But how stop all subscription when view is destroyed? I should also probably nullify presenter reference to avoid memory leak
但是当视图被销毁时如何停止所有订阅?我也应该使presenter引用无效以避免内存泄漏
2 个解决方案
#1
17
I think the best way to do that would be to:
我认为最好的办法是:
- Keep a
subscription
reference in theSiteAdapter.ViewHolder
- 在SiteAdapter.ViewHolder中保留订阅引用
-
unsubscribe
thesubscription
object inonBindViewHolder
(it's called when theViewHolder
is reused) - 取消订阅onBindViewHolder中的订阅对象(在重用ViewHolder时调用它)
- Keep the
CompositeSubscription
object in youradapter
- 将CompositeSubscription对象保留在适配器中
- Use the
onDetachedFromRecyclerView
method of yourAdapter
tounsubscribe
thecompositeSubscription
- 使用适配器的onDetachedFromRecyclerView方法取消订阅compositeSubscription
Like so:
像这样:
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
}
}
}
#2
0
For others which have the same problem: viewDetachedFromWindow in the adapter is only called when the adapter is set to null in the onPause (Activity, Fragment) or onDetachFromWindow (Activity, Fragment)
对于具有相同问题的其他问题:只有在onPause(Activity,Fragment)或onDetachFromWindow(Activity,Fragment)中将适配器设置为null时,才会调用适配器中的viewDetachedFromWindow
recyclerview.setAdapter(null)
recyclerview.setAdapter(空)
Then you get viewDetachedFromWindow(...) where you can release your internal states and subscriptions. I would setup your subscriptions in on bind, make sure before every bind call you relase old subscriptions as a view can be recycled.
然后,您将获得viewDetachedFromWindow(...),您可以在其中释放内部状态和订阅。我将在on bind中设置您的订阅,确保在每次绑定调用之前您重新关联旧订阅,因为视图可以被回收。
Another possibility is to inflate a custom view instead of only a layout in your factory. Then you can make the cleanup in the custom view onDetachFromWindow(). You get the onDetachedFromWindow also without setting the adapter to null.
另一种可能性是在工厂中扩展自定义视图而不仅仅是布局。然后,您可以在自定义视图onDetachFromWindow()中进行清理。您也可以在不将适配器设置为null的情况下获得onDetachedFromWindow。
#1
17
I think the best way to do that would be to:
我认为最好的办法是:
- Keep a
subscription
reference in theSiteAdapter.ViewHolder
- 在SiteAdapter.ViewHolder中保留订阅引用
-
unsubscribe
thesubscription
object inonBindViewHolder
(it's called when theViewHolder
is reused) - 取消订阅onBindViewHolder中的订阅对象(在重用ViewHolder时调用它)
- Keep the
CompositeSubscription
object in youradapter
- 将CompositeSubscription对象保留在适配器中
- Use the
onDetachedFromRecyclerView
method of yourAdapter
tounsubscribe
thecompositeSubscription
- 使用适配器的onDetachedFromRecyclerView方法取消订阅compositeSubscription
Like so:
像这样:
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
}
}
}
#2
0
For others which have the same problem: viewDetachedFromWindow in the adapter is only called when the adapter is set to null in the onPause (Activity, Fragment) or onDetachFromWindow (Activity, Fragment)
对于具有相同问题的其他问题:只有在onPause(Activity,Fragment)或onDetachFromWindow(Activity,Fragment)中将适配器设置为null时,才会调用适配器中的viewDetachedFromWindow
recyclerview.setAdapter(null)
recyclerview.setAdapter(空)
Then you get viewDetachedFromWindow(...) where you can release your internal states and subscriptions. I would setup your subscriptions in on bind, make sure before every bind call you relase old subscriptions as a view can be recycled.
然后,您将获得viewDetachedFromWindow(...),您可以在其中释放内部状态和订阅。我将在on bind中设置您的订阅,确保在每次绑定调用之前您重新关联旧订阅,因为视图可以被回收。
Another possibility is to inflate a custom view instead of only a layout in your factory. Then you can make the cleanup in the custom view onDetachFromWindow(). You get the onDetachedFromWindow also without setting the adapter to null.
另一种可能性是在工厂中扩展自定义视图而不仅仅是布局。然后,您可以在自定义视图onDetachFromWindow()中进行清理。您也可以在不将适配器设置为null的情况下获得onDetachedFromWindow。