2015-07-13 3 views
3

My RecyclerView создает утечку памяти каждый раз, когда его деятельность была воссоздана. У меня есть google, но я смог найти любое решение для этого. Активность уничтожается с помощью кнопки «Назад» и создается при нажатии кнопки «Моя основная активность». Я также опубликовал результат утечки канарейки. Спасибо.RecyclerView утечки при воссоздании

//CommentListAdapater 
package com.support.android.designlibdemo.adapters; 

import android.content.Context; 
import android.support.v7.widget.RecyclerView; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.TextView; 

import com.squareup.otto.Subscribe; 
import com.support.android.designlibdemo.MyApplication; 
import com.support.android.designlibdemo.R; 
import com.support.android.designlibdemo.events.CommentsLoadEvent; 
import com.support.android.designlibdemo.events.EventFinished; 
import com.support.android.designlibdemo.events.NetworkErrorEvent; 
import com.support.android.designlibdemo.models.RedditComment; 
import com.support.android.designlibdemo.models.RedditObject; 
import com.support.android.designlibdemo.models.RedditResponse; 
import com.support.android.designlibdemo.models.RedditThread; 
import com.support.android.designlibdemo.services.RedditService; 

import java.util.ArrayList; 
import java.util.List; 

import retrofit.Callback; 
import retrofit.RetrofitError; 
import retrofit.client.Response; 

public class CommentListAdapter extends RecyclerView.Adapter<CommentListAdapter.ViewHolder> { 
    private List<RedditComment> mValues = new ArrayList(); 
    private Context mContext; 
    private static final String SUBREDDIT_NAME = "subreddit_name"; 
    private static final String THREAD_ID = "thread_id"; 
    private static final String THREAD_NAME = "thread_name"; 

    public CommentListAdapter(Context context) { 
     mContext = context; 
    } 

    public class ViewHolder extends RecyclerView.ViewHolder { 
     public View mView; 
     public TextView mBody; 
     public TextView mAuthor; 

     public ViewHolder(View itemView) { 
      super(itemView); 
      mView = itemView; 
      mBody = (TextView) itemView.findViewById(R.id.body); 
      mAuthor = (TextView) itemView.findViewById(R.id.author_name); 
     } 
    } 

    @Override 
    public void onBindViewHolder(CommentListAdapter.ViewHolder holder, int position) { 
     if (mValues.get(position).selftext == null) { 
      holder.mBody.setText(mValues.get(position).body); 
     } else { 
      holder.mBody.setText(mValues.get(position).selftext); 
     } 
     holder.mAuthor.setText(mValues.get(position).author); 
    } 

    @Override 
    public int getItemCount() { 
     if (mValues == null) { 
      return 0; 
     } 
     return mValues.size(); 
    } 

    @Override 
    public CommentListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
     // create a new view 
     View v = LayoutInflater.from(parent.getContext()) 
       .inflate(R.layout.activity_comment_holder, parent, false); 

     ViewHolder vh = new ViewHolder(v); 
     return vh; 
    } 

    @Subscribe 
    public void fetchData(final CommentsLoadEvent event) { 
     RedditService.Implementation.get().getThreadComments(event.subredditName, event.threadId, 
       new Callback<List<RedditResponse<RedditComment>>>() { 
        @Override 
        public void success(List<RedditResponse<RedditComment>> redditResponses, Response response) { 
         mValues.clear(); 
         for (RedditResponse rr : redditResponses) { 
          RedditComment rc = (RedditComment) rr.getData(); 
          for (RedditObject obj : rc.children) { 
           if (obj instanceof RedditThread) { 
            RedditThread t = (RedditThread) obj; 
            RedditComment c = new RedditComment(); 
            c.selftext = t.selftext; 
            c.author = t.author; 
            mValues.add(c); 
           } else { 
            RedditComment c = (RedditComment) obj; 
            mValues.add(c); 
           } 
           notifyDataSetChanged(); 
           MyApplication.getBus().post(new EventFinished()); 
          } 
         } 
        } 

        @Override 
        public void failure(RetrofitError error) { 
         MyApplication.getBus().post(new NetworkErrorEvent(error, mContext)); 
        } 
       } 
     ); 

    } 

    @Override 
    public void onAttachedToRecyclerView(RecyclerView recyclerView) { 
     super.onAttachedToRecyclerView(recyclerView); 
     MyApplication.getBus().register(this); 
    } 

    @Override 
    public void onDetachedFromRecyclerView(RecyclerView recyclerView) { 
     super.onDetachedFromRecyclerView(recyclerView); 
     MyApplication.getBus().unregister(this); 
    } 
} 

//CommentActivity 
package com.support.android.designlibdemo.activities; 

import android.content.Intent; 
import android.os.Bundle; 
import android.support.v4.widget.SwipeRefreshLayout; 
import android.support.v7.widget.LinearLayoutManager; 
import android.support.v7.widget.RecyclerView; 
import android.support.v7.widget.Toolbar; 

import com.squareup.otto.Subscribe; 
import com.support.android.designlibdemo.MyApplication; 
import com.support.android.designlibdemo.R; 
import com.support.android.designlibdemo.adapters.CommentListAdapter; 
import com.support.android.designlibdemo.events.CommentsLoadEvent; 
import com.support.android.designlibdemo.events.EventFinished; 

public class CommentActivity extends BaseActivity { 
    public static final String SUBREDDIT_NAME = "subreddit_name"; 
    public static final String THREAD_ID = "thread_id"; 
    public static final String THREAD_NAME = "thread_name"; 

    private final String TAG = getClass().getSimpleName(); 
    private RecyclerView mRecyclerView; 
    private SwipeRefreshLayout mSwipeRefreshLayout; 
    private CommentListAdapter mAdapter; 
    private RecyclerView.LayoutManager mLayoutManager; 
    private String mSubredditName; 
    private String mThreadName; 
    private String mThreadId; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 
     Intent intent = getIntent(); 
     mSubredditName = intent.getStringExtra(SUBREDDIT_NAME); 
     mThreadName = intent.getStringExtra(THREAD_NAME); 
     mThreadId = intent.getStringExtra(THREAD_ID); 

     toolbar.setSubtitle(mThreadName); 
     toolbar.setTitle(mSubredditName); 
     setToolbar(); 
     setupRecyclerView(); 
    } 

    @Override 
    protected boolean hasCustomIcon() { 
     return false; 
    } 

    @Override 
    protected int getLayout() { 
     return R.layout.activity_comment; 
    } 

    private void setupRecyclerView() { 
     if (mRecyclerView == null) { 

      mRecyclerView = (RecyclerView) findViewById(R.id.comment_recycler); 
      mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh); 
     } 

     if (mLayoutManager == null) { 
      // use a linear layout manager 
      mLayoutManager = new LinearLayoutManager(this); 
      mRecyclerView.setLayoutManager(mLayoutManager); 
      mSwipeRefreshLayout.setColorSchemeColors(R.color.colorAccent, 
                R.color.color_primary_dark, 
                R.color.frame_background); 
      mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { 
       @Override 
       public void onRefresh() { 
        MyApplication.getBus().post(new CommentsLoadEvent(
            mSubredditName, mThreadId) 
        ); 
       } 
      }); 
     } 

     if (mAdapter == null) { 
      mAdapter = new CommentListAdapter(this); 
      mRecyclerView.setAdapter(mAdapter); 
      mSwipeRefreshLayout.setRefreshing(true); 
      MyApplication.getBus().post(new CommentsLoadEvent(
          mSubredditName, mThreadId) 
      ); 
     } 
    } 

    @Subscribe 
    public void stopSwipe(final EventFinished event) { 
     mSwipeRefreshLayout.setRefreshing(false); 
    } 

    @Override 
    public void onPause() { 
     super.onPause(); 
     MyApplication.getBus().unregister(this); 
    } 

    @Override 
    public void onResume() { 
     super.onResume(); 
     MyApplication.getBus().register(this); 
    } 
} 

//MyApplication 
package com.support.android.designlibdemo; 

import android.app.Application; 

import com.crashlytics.android.Crashlytics; 
import com.squareup.leakcanary.LeakCanary; 
import com.squareup.otto.Bus; 

import io.fabric.sdk.android.Fabric; 

public class MyApplication extends Application { 
    private static Bus _bus; 

    @Override public void onCreate() { 
     super.onCreate(); 
     Fabric.with(this, new Crashlytics()); 
     LeakCanary.install(this); 
    } 

    public static Bus getBus() { 
     if (_bus == null) { 
      _bus = new Bus(); 
     } 
     return _bus; 
    } 
} 

leak image 1

leak image 2

ответ

1

private static Bus _bus; Это сохранение экземпляров из открепления. CommentListAdapter получает доступ к этому полю, в котором у вас есть экземпляр в CommentActivity. Это делает CommentActivity невозможным для освобождения (утечки).

Я не знаком с Отто, но вы не можете использовать его должным образом.

Если вы хотите обмениваться данными с адаптером, почему бы вам не сделать общедоступный метод в адаптере и не вызвать метод call.method()?

+0

Извините за мой поздний ответ. Спасибо за помощь. – kokeroulis

1

Когда ваш Activity уничтожен, ваш адаптер не отсоединяется автоматически от RecyclerView, поэтому адаптер все еще зарегистрирован в Отто, и он протекает. Вам необходимо вручную отменить регистрацию вашего адаптера при уничтожении Activity.