4

每次重新创建其活动时,我的 RecyclerView 都会造成内存泄漏。我有谷歌它,但我能够找到任何解决方案。该活动被后退按钮破坏,并在我的 mainActivity 进入按钮时被创建。我还发布了泄漏金丝雀的结果。谢谢你。

//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;
    }
}

泄漏图像 1

泄漏图像 2

4

2 回答 2

2

当您的Activity被销毁时,您的适配器不会自动与 分离RecyclerView,因此适配器仍然在 Otto 中注册并且它会泄漏。Activity当被销毁时,您需要手动取消注册您的适配器。

于 2015-09-12T14:15:19.830 回答
1

private static Bus _bus;这是从释放中保留实例。CommentListAdapter 正在访问此字段,您在 CommentActivity 中有一个实例。这使得 CommentActivity 不能被释放(泄漏)。

我对 Otto 不熟悉,但您可能无法正确使用它。

如果您想从活动到适配器进行通信,为什么不在适配器中创建公共方法并从活动调用 adapter.method() ?

于 2015-07-13T22:05:45.140 回答