RecyclerView适配器的生命周期是什么?

Eug*_*nov 48 android android-lifecycle android-recyclerview

我正在从适配器中的演示者请求图像:

  @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);
          })
    );
  }
Run Code Online (Sandbox Code Playgroud)

我应该在ViewHolder重新使用时取消订阅.这很容易.

但是当视图被销毁时如何停止所有订阅?我也应该使演示者引用无效以避免内存泄漏

Bar*_*ski 20

我认为最好的办法是:

  1. 保持subscription参考SiteAdapter.ViewHolder
  2. unsubscribe中的subscription对象onBindViewHolder(ViewHolder重用时调用)
  3. 保持CompositeSubscription对象在你的adapter
  4. 使用onDetachedFromRecyclerView你的方法AdapterunsubscribecompositeSubscription

像这样:

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 更改适配器时会调用`onDetachedFromRecyclerView`,但在配置更改时不会调用它:/ (4认同)
  • 很酷,所以当`RecyclerView`与活动分离时,调用适配器时没有方法 (2认同)

eug*_*man 6

对于其他有同样问题的人:仅当适配器在 onPause (Activity, Fragment) 或 onDetachFromWindow (Activity, Fragment) 中设置为 null 时才调用适配器中的 viewDetachedFromWindow

recyclerview.setAdapter(null)

然后你会得到 viewDetachedFromWindow(...) ,你可以在那里发布你的内部状态和订阅。我会在绑定时设置您的订阅,确保在每次绑定调用之前您将旧订阅释放为可以回收的视图。

另一种可能性是膨胀自定义视图,而不仅仅是工厂中的布局。然后您可以在自定义视图 onDetachFromWindow() 中进行清理。您也可以在不将适配器设置为 null 的情况下获得 onDetachedFromWindow。