RecyclerView在片段泄漏父活动

时间:2017-02-20 12:10:16

标签: android android-fragments memory-leaks android-recyclerview android-adapter

在我的应用程序中,我有一个包含3个片段的ViewPage的MainActivity。其中两个片段有一些由一些CardView填充的RecyclerView。一切正常,但在安装金丝雀泄漏后,我注意到我的RecyclerViews正在泄漏MainActivity:, the last 3 lines of CanaryLeaks look like this :

看起来应该有静态引用阻止GC完成他的工作,但我的代码中没有这样的东西。我试过打电话

recyclerView.setAdapter(null) or recyclerView.cleanup()

在我的Fragment的onDestroy / onDestroyView上但泄漏仍在那里

这是我的片段:

 @Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {     

   //here some FirebaseDatabasereference

    recyclerView = (RecyclerView)inflater.inflate(R.layout.event_fragment_layout, container,false);
    recyclerView.setHasFixedSize(true);
    recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
    return recyclerView;

} 

public void onStart() {
    super.onStart();

    firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<Event, MyEventViewHolder>(

            Event.class,
            R.layout.event_card,
            MyEventViewHolder.class,
            myDatabase.child("Events").orderByChild(ordering[orderingSelector]),

    ) {
        @Override
        protected void populateViewHolder(final MyEventViewHolder viewHolder, final Event model, final int position) {
        final String post_key = getRef(position).getKey();

            viewHolder.setEventName(model.getEventName());
            viewHolder.setEventImage(getApplicationContext(),model.getEventImagePath());

            ValueEventListener likeCheckerListener = new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                    if(dataSnapshot.child(post_key).hasChild(currentUser.getUid())){
                        viewHolder.setThumbDown();
                        mDatabaseLike.removeEventListener(this);
                    }else{
                        viewHolder.setThumbUp();
                        mDatabaseLike.removeEventListener(this);
                    }
                    mDatabaseLike.removeEventListener(this);
                }

                @Override
                public void onCancelled(DatabaseError databaseError) {

                }
            };
            mDatabaseLike.addValueEventListener(likeCheckerListener);

recyclerView.setAdapter(firebaseRecyclerAdapter);
}

 @Override
public void onStop() {
    super.onStop();
    recyclerView.setAdapter(null);
}

@Override
public void onDestroy() {
    super.onDestroy();
    recyclerView.setAdapter(null);
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    recyclerView.setAdapter(null);
}

这是我的ViewHolder:

public class MyEventViewHolder extends RecyclerView.ViewHolder{

View mView;
CircularImageView cardProfile;
TextView cardLikes,cardDate,cardTime;
TextView event_name,joiners,etaMedia,maleSex,cardPrice,femaleSex;
FABRevealLayout mFABRevealLayout;
Button chiudi;
FloatingActionButton fabLike;



public MyEventViewHolder(View itemView) {
    super(itemView);
    mView=itemView;


    //removed some UI declaration and methods for readability
    cardTime = (TextView)mView.findViewById(R.id.cardTime);

    fabLike = (FloatingActionButton)mView.findViewById(R.id.fabLike);

}


public void setThumbUp (){
    fabLike.setImageResource(R.drawable.white_star_empty_24);
}
public void setThumbDown (){
    fabLike.setImageResource(R.drawable.white_star_full_24);
}

我不知道这是否有用,但泄漏通常是14KB到最大50KB。我已经能够解决所有其他泄漏问题,但这个问题让我疯狂了

2 个答案:

答案 0 :(得分:0)

您的recyclerView是静态的吗? 无论如何,你应该在onDestroyView中将recyclerView设置为null(recyclerView = null)(因为它在onCreateView中初始化)。

答案 1 :(得分:0)

我认为问题出现以下问题:

mDatabaseLike.addValueEventListener(likeCheckerListener);

你可以简单地评论它,看看是否还在发生泄漏。

您的likeCheckerListener是Anonymous类的Object,它引用了通过重写FirebaseRecyclerAdapter创建的Anonymous类,该类具有对您的活动的引用。这导致泄漏。

为了能够安全地处理这种情况,您应该为每个添加到mDatabase的ValueEventListener维护一个引用,并在onStop / onDestroy方法中将它们全部删除。

为此,你可能应该与听众和他们正在聆听的关键词保持一张地图。

还要考虑覆盖FirebaseRecyclerAdapter的onViewRecycled()方法,然后您还可以在回收视图时逐个删除侦听器,并且只侦听实际需要的项目上的事件。