为什么viewHolders没有被垃圾收集

时间:2017-07-21 12:49:50

标签: android

我有一项活动,其中我替换充当每个屏幕的片段。

我打开一个片段并向后按(从后台弹出它)然后返回到前一个片段。然后,我按下“启动GC”按钮

enter image description here

然后我转储Java堆并获取以下内容。

enter image description here

似乎片段FMenuForm没有从内存中释放出来,对吧?唯一似乎仍然在内存中的东西是RecyclerView中使用的ViewHolders ......但为什么呢?!

我已在片段的this.my_recycler_view.setAdapter(null)方法中设置onDestroy(),但它似乎仍然不想gc它。

enter image description here

修改

以下是AdapterViewHolders的代码。它们都是FMenuForm

的内部类
public class FMenuForm extends Fragment{


private RecyclerView list_view;

private AdapterMenuForm mAdapter;

private int mIndexSelected = 0;

//
// PRIVATE IMPLEMENTATION
//

private ListItemClickCallback.OnListItemClickListener<AdapterMenuForm.ListItem> mItemClickCallback =
        new ListItemClickCallback.OnListItemClickListener<AdapterMenuForm.ListItem>() {
            @Override
            public boolean onListItemClicked(View view, AdapterMenuForm.ListItem item, int position) {
                //TODO:
            }
        };

/** Some other method and fields here  */    


//
// ADAPTERS
//

private class AdapterMenuForm extends RecyclerView.Adapter<RowHolder> {

    private final int TYPE_SUBCATEGORY = 0;
    private final int TYPE_THEME = 1;

    private LayoutInflater mInflater;

    private ArrayList<ListItem> mSubcategories;

    //
    // CONSTRUCTOR
    //

    public AdapterMenuForm() {
        mInflater = LayoutInflater.from(getContext());
    }

    //
    // ADAPTER
    //


    @Override
    public int getItemCount() {
        return mSubcategories == null ? 0 : mSubcategories.size();
    }

    @Override
    public int getItemViewType(int position) {
        return mSubcategories.get(position).isSubcategory() ? TYPE_SUBCATEGORY : TYPE_THEME;
    }

    @Override
    public RowHolder onCreateViewHolder(ViewGroup viewGroup, int type) {
        if (type == TYPE_SUBCATEGORY) {
            return new RowHolderSubcategory(mInflater.inflate(R.layout.list_item_form_menu_parent, viewGroup, false));
        } else {
            return new RowHolderTheme(mInflater.inflate(R.layout.list_item_form_menu_child, viewGroup, false));
        }
    }

    @Override
    public void onBindViewHolder(final RowHolder holder, int position) {

        ListItem data = mSubcategories.get(position);

        //Label
        holder.text.setText(
                data.isSubcategory()
                        ? data.item.subcategory.name
                        : data.item.theme.name);

        //Highlight
        holder.itemView.setActivated(mIndexSelected == position);

        //Check icon
        //TODO:
        holder.icon.setActivated(position % 2 == 0);

        //Arrow
        holder.arrow.setVisibility(
                data.children.size() == 0 ? View.INVISIBLE : View.VISIBLE
        );
        holder.arrow.setImageResource(
                data.isExpanded ? R.drawable.selector_expandable_icon_up : R.drawable.selector_expandable_icon_down
        );

        //Click listeners
        holder.itemView.setOnClickListener(new ListItemClickCallback<ListItem>(mItemClickCallback, data, position));
        holder.arrow.setOnClickListener(new ListItemClickCallback<ListItem>(mArrowClickCallback, data, position));


    }

    //
    // PUBLIC IMPLEMENTATION
    //

    public void setData(final FormOptionsListItem items) {

        /** Long method. Nothing interesting. Populated mSubcategories*/

    }

    //
    // CLASSES
    //

    private class ListItem {

        boolean isExpanded = false;

        FormOptionItem item;

        ArrayList<ListItem> children = new ArrayList<>();

        public ListItem(FormOptionItem item) {
            this.item = item;
        }

        public boolean isSubcategory() {
            return item.remote_theme_id.contentEquals("0");
        }

        public boolean isTheme() {
            return !item.remote_theme_id.contentEquals("0");
        }

    }

}

public static class RowHolder extends RecyclerView.ViewHolder {
    private TextView text;
    private View icon;
    private ImageView arrow;

    public RowHolder(View view) {
        super(view);
        this.text = (TextView) view.findViewById(R.id.list_item_form_menu_text);
        this.icon = view.findViewById(R.id.list_item_form_check_icon);
        this.arrow = (ImageView) view.findViewById(R.id.list_item_form_check_icon_arrow);
    }
}

public static class RowHolderSubcategory extends RowHolder {
    public RowHolderSubcategory(View view) {
        super(view);
    }
}

public static class RowHolderTheme extends RowHolder {
    public RowHolderTheme(View view) {
        super(view);
    }
}

}

1 个答案:

答案 0 :(得分:0)

问题是你在一个类中定义了AdapterMenuForm,但它不是静态的。请遵循EffectiveJava中的文档,这不合法。(item22

  

如果声明一个不需要访问封闭实例的成员类,则始终将static修饰符放在其声明中,使其成为静态成员类而非非静态成员类。如果省略此修饰符,则每个实例将对其封闭实例具有无关的引用。存储此引用会花费时间和空间,并且可能导致封闭实例被保留,否则它将有资格进行垃圾回收(第6项)。如果您需要在没有封闭实例的情况下分配实例,则您将无法执行此操作,因为非静态成员类实例需要具有封闭实例。

解决方案是,尝试使您的Adapter类成为嵌套的静态类或将其移动到另一个文件夹:adapters?然后创建constructor以初始化您的mSubCategories