Android RecyclerView适配器don';我不想重复使用视图持有者

Android RecyclerView适配器don';我不想重复使用视图持有者,android,android-fragments,android-recyclerview,Android,Android Fragments,Android Recyclerview,我面临着内存泄漏的问题。 我有一个带有FragmentStatePagerAdapter的片段,里面有一个片段(还有更多,我留下一个只是为了测试)。 此片段包含具有几个不同视图持有者的RecyclerView 例如,这是一个简单的ViewHolder,仅在RecyclerView中的一个位置用作标题 public class CurrencyViewHolder extends RecyclerView.ViewHolder { @BindView(R.id.currency_date

我面临着内存泄漏的问题。 我有一个带有
FragmentStatePagerAdapter
的片段,里面有一个片段(还有更多,我留下一个只是为了测试)。 此片段包含具有几个不同视图持有者的RecyclerView

例如,这是一个简单的
ViewHolder
,仅在
RecyclerView
中的一个位置用作标题

public class CurrencyViewHolder extends RecyclerView.ViewHolder {

    @BindView(R.id.currency_date)
    TextView currencyDate;
    @BindView(R.id.currency_usd)
    TextView currencyUsd;
    @BindView(R.id.currency_eur)
    TextView currencyEur;
    @BindView(R.id.currency_info)
    LinearLayout currencyInfo;

    public CurrencyViewHolder(View itemView, boolean nightMode) {
        super(itemView);
        ButterKnife.bind(this, itemView);
    }

    public void bind(CbrResponse response) {
        currencyDate.setText(String.format("asdsdf %s", response.getDate()));
        currencyUsd.setText(String.format("USD %,.2f", response.getUSD().getValue()));
        currencyEur.setText(String.format("EUR %,.2f", response.getEUR().getValue()));
    }
}
但是,正如你所看到的,在这张照片上

我有12个这个类的实例。我已经对这个片段中的另一个片段进行了12次交易,出于某种原因,我的
视图持有者被重新创建

我认为这是导致我内存泄漏的原因。我不确定你想要哪段代码,所以我放了一些适配器方法,以防你想看到它

NewsListRecyclerAdapter
是我的适配器,下面的代码在这里执行。请注意,此类的intance只创建一次

UPD

这是我的带有ViewPager的framgnet:

public class PagerListsFragment extends NightModeFragment {
    private final String LOG_TAG = PagerListsFragment.class.getSimpleName();


    @BindView(R.id.circlePagerListsIndicator)
    TextCirclePageIndicator pageIndicator;
    @BindView(R.id.settings_button)
    ImageButton settingsButton;
    @BindView(R.id.pager_lists_header)
    FrameLayout pagerListsHeader;
    @BindView(R.id.pagerLists)
    ViewPager viewPager;
    @BindView(R.id.linear_layout)
    LinearLayout linearLayout;

//    ArticlesFragment articlesFragment;
//    FavouritesFragment favouritesFragment;


    PagerListsFragmentAdapter fragmentAdapter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("PagerListsFragment", "onCreate");
        fragmentAdapter = new PagerListsFragmentAdapter(getContext(), getChildFragmentManager());
//        articlesFragment = new ArticlesFragment();
//        favouritesFragment = new FavouritesFragment();
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        Log.d("PagerListsFragment", "onViewCreated");
        viewPager = (ViewPager) view.findViewById(R.id.pagerLists);
        viewPager.setAdapter(fragmentAdapter);

        viewPager.setPageMargin((int) getResources().getDimension(R.dimen.lists_pager_margin));

        pageIndicator =
                (TextCirclePageIndicator) view.findViewById(R.id.circlePagerListsIndicator);
        pageIndicator.setViewPager(viewPager);

        pagerListsHeader = (FrameLayout) view.findViewById(R.id.pager_lists_header);
        linearLayout = (LinearLayout) view.findViewById(R.id.linear_layout);

        final int topMarginUp = 0;
        final int topMarginDown = getResources().getDimensionPixelSize(R.dimen.toolbar_height);
        setTopMargin(linearLayout, topMarginDown);

        ImageButton settingsButton = (ImageButton) view.findViewById(R.id.settings_button);
        settingsButton.setOnClickListener(v -> ((MainActivity) getActivity()).openSettings());
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Log.d("PagerListsFragment", "onDestroyView");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("PagerListsFragment", "onDestroy");
    }

    @Override
    protected int getLayoutResource() {
        return R.layout.fragment_list_paged;
    }


    private void setTopMargin(View view, int topMarginInPx) {
        ViewGroup.MarginLayoutParams layoutParams =
                (ViewGroup.MarginLayoutParams) view.getLayoutParams();
        layoutParams.topMargin = topMarginInPx;
        view.requestLayout();
    }

    public static PagerListsFragment getInstace(Bundle extra) {
        PagerListsFragment fragment = new PagerListsFragment();
        fragment.setArguments(extra);
        return fragment;
    }
}
这是我的片段,其中RecyclerView是:

public class NewsFragment extends BaseNewsFragment implements NewsViewState,
        TeaserViewHolder.OnItemClickListener {

    private final Category category = new Category(Category.NEWS);

    @InjectPresenter
    NewsPresenter presenter;

    protected NewsListRecyclerAdapter adapter;
    protected EndlessRecyclerOnScrollListener scrollListener;

    @BindView(R.id.news_recycler)
    protected RecyclerView newsRecycler;
    @BindView(R.id.refresh)
    protected SwipeRefreshLayout refresh;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("NewsFragment", "onCreate");
        adapter = new NewsListRecyclerAdapter(getActivity(), this);
        presenter.loadNewsAndCurrency(0, true, category);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        LinearLayoutManager manager = new LinearLayoutManager(getActivity());

        scrollListener = new EndlessRecyclerOnScrollListener(manager) {
            @Override
            public void onLoadMore(int current_page) {
                presenter.loadNewsAndCurrency(adapter.getItemCount(), false, category);
            }
        };
        newsRecycler.addOnScrollListener(scrollListener);
        newsRecycler.setItemAnimator(null);
        newsRecycler.setLayoutManager(manager);
        newsRecycler.setAdapter(adapter);

        refresh.setOnRefreshListener(() -> {
            scrollListener.reset(0, true);
            presenter.loadNewsAndCurrency(0, true, category);
            if (!DEBUG) {
                FlurryAgent.logEvent(FlurryHelper.USER_NEWS_LIST);
            }
        });
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Log.d("NewsFragment", "onDestroy");
        if (newsRecycler != null) {
            newsRecycler.setAdapter(null);
        }
    }

    @Override
    public void onTeasersLoaded(List<NewsListItem> teasers, boolean refresh) {
        adapter.addAll(teasers, refresh);
    }

    @Override
    public void removeTeaser(NewsListItem item) {
        Log.d("BaseNewsFragment", "Removing item.getType():" + item.getType());
        if (item.getTeaser().getCategoryId() == category.getCategoryInt()) {
            adapter.remove(item);
        }
    }

    @Override
    public void addTeaser(NewsListItem item) {
        if (item.getTeaser().getCategoryId() == category.getCategoryInt()) {
            adapter.add(item);
        }
    }

    @Override
    public void onCurrencyLoaded(NewsListItem currencyItem) {
        adapter.add(currencyItem);
    }

    @Override
    public void onItemClick(NewsListItem teaser) {
        ((MainActivity) getActivity()).onNewsSelected(teaser.getTeaser().getUuid(), category.getCategoryInt());
        adapter.add(teaser);
    }

    @Override
    public void setNightMode() {
        adapter.setNightMode(isNightMode);
        newsRecycler.setBackgroundColor(getCurrentBackgroundColor());
    }

    @Override
    public void hideProgress() {
        refresh.setRefreshing(false);
    }

    @Override
    public void showProgress() {
        refresh.setRefreshing(true);
    }
}
公共类NewsFragment扩展BaseNewsFragment实现NewsViewState,
triserviewholder.OnItemClickListener{
私有最终类别=新类别(Category.NEWS);
@注射者
新闻主持人;
受保护的NewsListRecyclerAdapter适配器;
受保护的EndlesRecycleronScrollListener scrollListener;
@BindView(R.id.news\u回收商)
受保护的回收站查看新闻回收站;
@BindView(R.id.refresh)
受保护的布局刷新;
@凌驾
创建时的公共void(@Nullable Bundle savedInstanceState){
super.onCreate(savedInstanceState);
Log.d(“新闻片段”、“onCreate”);
adapter=新的NewsListRecyclerAdapter(getActivity(),this);
presenter.LoadNews和Currency(0,true,类别);
}
@凌驾
已创建视图上的公共void(视图,捆绑保存状态){
super.onViewCreated(视图,savedInstanceState);
LinearLayoutManager=newlinearlayoutmanager(getActivity());
scrollListener=新的EndlesRecycleronScrollListener(管理器){
@凌驾
public void onLoadMore(int当前页面){
loadNewsAndCurrency(adapter.getItemCount(),false,category);
}
};
addOnScrollListener(scrollListener);
newsRecycler.setItemAnimator(空);
newsRecycler.setLayoutManager(管理器);
newsRecycler.setAdapter(适配器);
refresh.setOnRefreshListener(()->{
scrollListener.reset(0,true);
presenter.LoadNews和Currency(0,true,类别);
如果(!调试){
FlurryAgent.logEvent(FlurryHelper.USER\u新闻列表);
}
});
}
@凌驾
公共无效onDestroyView(){
super.onDestroyView();
Log.d(“新闻片段”、“onDestroy”);
if(新闻回收器!=null){
newsRecycler.setAdapter(null);
}
}
@凌驾
public void ontasersloaded(列表摘要、布尔刷新){
adapter.addAll(摘要、刷新);
}
@凌驾
公共无效删除器(NewsListItem){
Log.d(“BaseNewsFragment”,“删除item.getType():”+item.getType());
if(item.getTeaser().getCategoryId()==category.getCategoryInt()){
适配器。移除(项目);
}
}
@凌驾
public void addstriser(NewsListItem){
if(item.getTeaser().getCategoryId()==category.getCategoryInt()){
添加(项目);
}
}
@凌驾
加载currencyItem时的公共无效(NewsListItem currencyItem){
adapter.add(currencyItem);
}
@凌驾
公共链接(NewsListItem摘要){
((MainActivity)getActivity()).onNewsSelected(trister.getTeaser().getUuid(),category.getCategoryInt());
适配器。添加(摘要);
}
@凌驾
公共void setNightMode(){
adapter.setNightMode(isNightMode);
setBackgroundColor(getCurrentBackgroundColor());
}
@凌驾
public void hideProgress(){
refresh.setRefreshing(false);
}
@凌驾
公共服务进展{
refresh.setRefreshing(true);
}
}

我无法滑动片段,因为我在ViewPager中只剩下一个片段(只是为了测试。)

您的片段被重新创建了多少次?12
ViewHolder
计数可能来自使用
FragmentStatePagerAdapter
刷卡时重新创建的新
Fragment
,从而重新创建
RecyclerView
RecyclerAdapter
ViewHolder


在查看堆之前,您是否尝试过使用
启动GC
?它们可能是
GC
等待收集已销毁的旧视图,但由于有足够的可用内存,
GC
将不会收集这些视图。

您的片段被重新创建了多少次?12
ViewHolder
计数可能来自使用
FragmentStatePagerAdapter
刷卡时重新创建的新
Fragment
,从而重新创建
RecyclerView
RecyclerAdapter
ViewHolder


在查看堆之前,您是否尝试过使用
启动GC
?它们可能是
GC
等待收集已销毁的旧视图,但由于有足够的可用内存,
GC
将不会收集这些内容。

您真正的意思是“我已将12个事务从这一个片段收集到另一个片段”?您使用过ViewPager吗?@Ewoks我的意思是我在这个recyclerView片段和其他片段之间导航了12次。@Hareshchelana是的,我使用ViewPager与recyclerView一起存储片段。FragmentStatePagerAdapter是他的改编者我不确定我是否看到了这个问题。。您的RecyclerView有12个visi
public class NewsFragment extends BaseNewsFragment implements NewsViewState,
        TeaserViewHolder.OnItemClickListener {

    private final Category category = new Category(Category.NEWS);

    @InjectPresenter
    NewsPresenter presenter;

    protected NewsListRecyclerAdapter adapter;
    protected EndlessRecyclerOnScrollListener scrollListener;

    @BindView(R.id.news_recycler)
    protected RecyclerView newsRecycler;
    @BindView(R.id.refresh)
    protected SwipeRefreshLayout refresh;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("NewsFragment", "onCreate");
        adapter = new NewsListRecyclerAdapter(getActivity(), this);
        presenter.loadNewsAndCurrency(0, true, category);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        LinearLayoutManager manager = new LinearLayoutManager(getActivity());

        scrollListener = new EndlessRecyclerOnScrollListener(manager) {
            @Override
            public void onLoadMore(int current_page) {
                presenter.loadNewsAndCurrency(adapter.getItemCount(), false, category);
            }
        };
        newsRecycler.addOnScrollListener(scrollListener);
        newsRecycler.setItemAnimator(null);
        newsRecycler.setLayoutManager(manager);
        newsRecycler.setAdapter(adapter);

        refresh.setOnRefreshListener(() -> {
            scrollListener.reset(0, true);
            presenter.loadNewsAndCurrency(0, true, category);
            if (!DEBUG) {
                FlurryAgent.logEvent(FlurryHelper.USER_NEWS_LIST);
            }
        });
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Log.d("NewsFragment", "onDestroy");
        if (newsRecycler != null) {
            newsRecycler.setAdapter(null);
        }
    }

    @Override
    public void onTeasersLoaded(List<NewsListItem> teasers, boolean refresh) {
        adapter.addAll(teasers, refresh);
    }

    @Override
    public void removeTeaser(NewsListItem item) {
        Log.d("BaseNewsFragment", "Removing item.getType():" + item.getType());
        if (item.getTeaser().getCategoryId() == category.getCategoryInt()) {
            adapter.remove(item);
        }
    }

    @Override
    public void addTeaser(NewsListItem item) {
        if (item.getTeaser().getCategoryId() == category.getCategoryInt()) {
            adapter.add(item);
        }
    }

    @Override
    public void onCurrencyLoaded(NewsListItem currencyItem) {
        adapter.add(currencyItem);
    }

    @Override
    public void onItemClick(NewsListItem teaser) {
        ((MainActivity) getActivity()).onNewsSelected(teaser.getTeaser().getUuid(), category.getCategoryInt());
        adapter.add(teaser);
    }

    @Override
    public void setNightMode() {
        adapter.setNightMode(isNightMode);
        newsRecycler.setBackgroundColor(getCurrentBackgroundColor());
    }

    @Override
    public void hideProgress() {
        refresh.setRefreshing(false);
    }

    @Override
    public void showProgress() {
        refresh.setRefreshing(true);
    }
}