0

I have a RecyclerView in a Fragment. I'm sure Memory Leak came from RecyclerView because when I add RecyclerView, Memory leak appears.

This is my RecyclerView Adapter:

public class TabsAdapter extends RecyclerView.Adapter<TabsAdapter.SetViewHolder> {

private Context context;
private List<TabsModel> items = Collections.emptyList();
private TabsDatabaseHelper databaseHelper;
private Dialog dialog;

public TabsAdapter(Context context, List<TabsModel> items, Dialog dialog) {
    databaseHelper = new TabsDatabaseHelper(context);
    this.context = context;
    this.items = items;
    this.dialog = dialog;
}

@NonNull
@Override
public TabsAdapter.SetViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.item_tabs, parent, false);
    return new SetViewHolder(view);
}

@Override
public void onBindViewHolder(@NonNull TabsAdapter.SetViewHolder holder, final int position) {
    //I clean here codes, By removing the code here, Memory Leak again occur
}

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

static class SetViewHolder extends RecyclerView.ViewHolder {

    private ImageView ivShot, ivRemove;
    private TextView tvTitle, tvUrl;
    private ConstraintLayout constraintLayout;

    private SetViewHolder(@NonNull View itemView) {
        super(itemView);
        ivShot = itemView.findViewById(R.id.iv_item_tabs);
        ivRemove = itemView.findViewById(R.id.iv_clear_item_tabs);
        tvTitle = itemView.findViewById(R.id.tv_title_item_tabs);
        tvUrl = itemView.findViewById(R.id.tv_url_item_tabs);
        constraintLayout = itemView.findViewById(R.id.const_item_tabs);
    }
}
}

And in Fragment:

    tabsModelArrayList.clear();
    tabsModelArrayList = tabsDatabaseHelper.getData();
    tabsAdapter = new TabsAdapter(context, tabsModelArrayList, getDialog());
    recyClerView.setHasFixedSize(true);
    LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context);
    recyClerView.setLayoutManager(linearLayoutManager);
    recyClerView.setAdapter(tabsAdapter);

So the Memory Leak is :

leakcanary library

I try to set null view in adapter:

@Override
public void onViewDetachedFromWindow(@NonNull SetViewHolder holder) {
    super.onViewDetachedFromWindow(holder);
    holder.constraintLayout = null;
    holder.ivRemove = null;
    holder.ivShot = null;
    holder.tvTitle = null;
    holder.tvUrl = null;
}

Or in inDesroy Fragment, I set:

recyClerView.setAdapter(null);

But I have still that error. Can you help me?

----------Edit

I remove Context and DatabaseHelper from Adapter:

public class TabsAdapter extends RecyclerView.Adapter<TabsAdapter.SetViewHolder> {

private List<TabsModel> items = Collections.emptyList();
private Dialog dialog;

public TabsAdapter(List<TabsModel> items, Dialog dialog) {
    this.items = items;
    this.dialog = dialog;
}

@NonNull
@Override
public TabsAdapter.SetViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.item_tabs, parent, false);
    return new SetViewHolder(view);
}

@Override
public void onBindViewHolder(@NonNull TabsAdapter.SetViewHolder holder, final int position) {
    //I clean here codes, By removing the code here, Memory Leak again occur
}

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

static class SetViewHolder extends RecyclerView.ViewHolder {

    private ImageView ivShot, ivRemove;
    private TextView tvTitle, tvUrl;
    private ConstraintLayout constraintLayout;

    private SetViewHolder(@NonNull View itemView) {
        super(itemView);
        ivShot = itemView.findViewById(R.id.iv_item_tabs);
        ivRemove = itemView.findViewById(R.id.iv_clear_item_tabs);
        tvTitle = itemView.findViewById(R.id.tv_title_item_tabs);
        tvUrl = itemView.findViewById(R.id.tv_url_item_tabs);
        constraintLayout = itemView.findViewById(R.id.const_item_tabs);
    }
}

@Override
public void onViewDetachedFromWindow(@NonNull SetViewHolder holder) {
    super.onViewDetachedFromWindow(holder);
    holder.constraintLayout = null;
    holder.ivRemove = null;
    holder.ivShot = null;
    holder.tvTitle = null;
    holder.tvUrl = null;
}
}

But not fix the memory leak.

Marlen Schreiner
  • 535
  • 6
  • 14

1 Answers1

0

I can suggest you two things. Firstly you must not send Context in your recyclerView adapter constructor. In your code you used it in OnCreateView as parent.getContext anyway. Sending context in your constructor causes memory leaks. Secondly, I think you should not initialize DatabaseHelper in your constructor. You can do it before creating your adapter instance.Get your list from your database and send your list instead of DatabaseHelper in your constructor.

  • Thank you for your attention. I did what you said, You can see changes on my post, but not different. – Marlen Schreiner Apr 01 '20 at 11:39
  • @MarlenSchreiner You can apply this answer https://stackoverflow.com/a/46957469/7890123 You should add recyclerView.setAdapter(null); on your fragment. – Okan Serdaroğlu Apr 01 '20 at 12:16
  • I added this before. – Marlen Schreiner Apr 01 '20 at 12:27
  • @MarlenSchreiner Maybe you have to add View.OnAttachStateChangeListener in your onDestroyView() and setAdapter (null) in your onViewDetachedFromWindow method. Did you try it ? – Okan Serdaroğlu Apr 01 '20 at 12:41
  • @MarlenSchreiner Also you don't need to send Dialog in your adapter constructor. – Okan Serdaroğlu Apr 01 '20 at 13:00
  • I want my dialog to dismiss when clicking on recycler view Items. – Marlen Schreiner Apr 01 '20 at 13:40
  • Ok. Firstly try removing your Dialog in your adapter constructor. I think this can be cause this memory leak also. Generally you have to send only a list to your adapter constructor. You want to dismiss your dialog when clicking recyclerView items, thats ok, however sending this dialog in constructor is not a good way.You can dismiss your dialog with using an interface. – Okan Serdaroğlu Apr 01 '20 at 13:44
  • Optimal programming is really complicated! Thank you!! – Marlen Schreiner Apr 01 '20 at 14:13
  • Sorry! I need your advice, How the best way to use context in a Fragment? `getContext()?` or `container.getContext()` or `inflater.getContext()` or etc... . I read that the wrong context can make memory leak. – Marlen Schreiner Apr 02 '20 at 16:04
  • Try getActivity() Because Activity extends Context. Check here https://stackoverflow.com/questions/8215308/using-context-in-a-fragment – Okan Serdaroğlu Apr 02 '20 at 16:16
  • I think the dialog will likely cause the leak here. – MobDev Jun 05 '20 at 16:03