RecyclerView 适配器的生命周期是什么?
What is lifecycle for RecyclerView 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);
})
);
}
当 ViewHolder
被重新使用时,我应该退订。很简单。
但是如何在视图被销毁时停止所有订阅?我还应该取消演示者引用以避免内存泄漏
我认为最好的方法是:
- 在
SiteAdapter.ViewHolder
中保留一个 subscription
引用
unsubscribe
onBindViewHolder
中的 subscription
对象(重用 ViewHolder
时调用)
- 将
CompositeSubscription
对象保留在 adapter
中
- 使用
Adapter
的 onDetachedFromRecyclerView
方法来 unsubscribe
compositeSubscription
像这样:
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
}
}
}
其他遇到同样问题的人:
适配器中的 viewDetachedFromWindow 仅在 onPause (Activity, Fragment) 或 onDetachFromWindow (Activity, Fragment)
中将适配器设置为 null 时调用
recyclerview.setAdapter(空)
然后您将获得 viewDetachedFromWindow(...),您可以在其中释放您的内部状态和订阅。我会在绑定时设置你的订阅,确保在每次绑定调用之前你 relase 旧订阅,因为视图可以被回收。
另一种可能性是扩充自定义视图,而不仅仅是工厂中的布局。然后您可以在自定义视图 onDetachFromWindow() 中进行清理。您也可以在不将适配器设置为 null 的情况下获得 onDetachedFromWindow。
可以调用public void onViewRecycled(@NonNull VH holder)
我正在向适配器中的演示者请求图像:
@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);
})
);
}
当 ViewHolder
被重新使用时,我应该退订。很简单。
但是如何在视图被销毁时停止所有订阅?我还应该取消演示者引用以避免内存泄漏
我认为最好的方法是:
- 在
SiteAdapter.ViewHolder
中保留一个 unsubscribe
onBindViewHolder
中的subscription
对象(重用ViewHolder
时调用)- 将
CompositeSubscription
对象保留在adapter
中
- 使用
Adapter
的onDetachedFromRecyclerView
方法来unsubscribe
compositeSubscription
subscription
引用
像这样:
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
}
}
}
其他遇到同样问题的人: 适配器中的 viewDetachedFromWindow 仅在 onPause (Activity, Fragment) 或 onDetachFromWindow (Activity, Fragment)
中将适配器设置为 null 时调用recyclerview.setAdapter(空)
然后您将获得 viewDetachedFromWindow(...),您可以在其中释放您的内部状态和订阅。我会在绑定时设置你的订阅,确保在每次绑定调用之前你 relase 旧订阅,因为视图可以被回收。
另一种可能性是扩充自定义视图,而不仅仅是工厂中的布局。然后您可以在自定义视图 onDetachFromWindow() 中进行清理。您也可以在不将适配器设置为 null 的情况下获得 onDetachedFromWindow。
可以调用public void onViewRecycled(@NonNull VH holder)