【问题标题】:What is lifecycle for RecyclerView adapter?RecyclerView 适配器的生命周期是什么?
【发布时间】:2016-06-07 08:50:36
【问题描述】:

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

  @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 被重复使用时,我应该取消订阅。这很容易。

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

【问题讨论】:

标签: android android-recyclerview android-lifecycle


【解决方案1】:

我认为最好的方法是:

  1. SiteAdapter.ViewHolder 中保留subscription 引用
  2. unsubscribe onBindViewHolder 中的subscription 对象(当ViewHolder 被重用时调用)
  3. CompositeSubscription 对象保留在您的adapter
  4. 使用AdapteronDetachedFromRecyclerView方法unsubscribecompositeSubscription

像这样:

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
        }
    }
}

【讨论】:

  • 酷,所以当RecyclerView 与活动分离时,适配器上没有方法被调用
  • 嗯...实际上有一个 - onDetachedFromRecyclerView 它可以轻松完成 recycle() 当前所做的事情。好主意:)
  • onDetachedFromRecyclerView 在您更改适配器时被调用,但在配置更改时不会被调用:/
  • @Miha_x64 好像是一个整体another issue
  • 如果订阅是不断监听更多数据的东西,你将如何解决同样的问题?对于上下文,我正在使用 firebase 数据更改侦听器。
【解决方案2】:

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

recyclerview.setAdapter(null)

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

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

【讨论】:

  • 如果订阅是不断监听更多数据的东西,你将如何解决同样的问题?对于上下文,我正在使用 firebase 数据更改侦听器。
  • @Adi 我会制作一个自定义视图并使用 onDetachFromWindow()
  • 我相信这不能解决问题。 onDetachFromWindow 在活动处于活动状态并且回收站视图滚动到窗口外时被调用。但是如果你关闭了一个活动,那么这个方法就不会为最后在窗口上可见的视图调用。所以会有内存泄漏。
  • @Adi onDetachFromWindow 也会在 Activity 被销毁时被调用,例如当你按下 android 后退按钮时。
  • 在这个问题上浪费了太多时间。谢谢。
【解决方案3】:

可以拨打public void onViewRecycled(@NonNull VH holder)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-12
    • 2012-12-08
    • 2018-04-15
    • 1970-01-01
    相关资源
    最近更新 更多