在我的RecyclerView.Adapter
我定义了这个界面:
public interface OnItemClickListener {
void onItemClick(View view, int position);
}
包含RecyclerView
的片段实现了此接口。
在4或5个方向更改后, LeakCanary 会报告内存泄漏:
我的Fragment
看起来像这样:
public class ImagesFragment extends Fragment implements ImageAdapter.OnItemClickListener {
private static final String IMAGES_FRAGMENT_TAG = "ImagesFragment";
private int SPAN_COUNT = 2;
private String categoryName;
private String categoryURL;
private int ImageCount;
protected RecyclerView mRecyclerView;
protected RecyclerView.LayoutManager mLayoutManager;
protected static ImageAdapter mAdapter;
@Override
public void onItemClick(View view, int position) {
Toast.makeText(mContext, "Clicked:" + String.valueOf(position), Toast.LENGTH_SHORT).show();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
this.categoryName = args.getString("category");
this.categoryURL = args.getString("URL");
this.ImageCount = args.getInt("Count");
setRetainInstance(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.images_recycler_view, container, false);
rootView.setTag(IMAGES_FRAGMENT_TAG);
mRecyclerView = (RecyclerView) rootView.findViewById(R.id.imagesRecyclerView);
mRecyclerView.addItemDecoration(new CategoryItemDecoration(px, SPAN_COUNT, mCurrentLayoutType));
mLayoutManager = new GridLayoutManager(getActivity().getApplicationContext(), SPAN_COUNT);
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new ImageAdapter(categoryURL, this.ImageCount, this);
mRecyclerView.setAdapter(mAdapter);
return rootView;
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putString(IMAGES_FRAGMENT_TAG, IMAGES_FRAGMENT_TAG);
super.onSaveInstanceState(outState);
}
@Override
public void onDestroyView() {
super.onDestroyView();
System.out.println("OnDestroyView");
if (mRecyclerView != null) {
mRecyclerView.setAdapter(null);
}
}
@Override
public void onDestroy() {
super.onDestroy();
RefWatcher refWatcher = MyApplication.getRefWatcher(getActivity());
refWatcher.watch(this);
}
}
我的Adapter
:
public class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ImagesViewHolder> {
private static final String IMAGES_FRAGMENT_TAG = "ImagesFragment";
private Context mContext;
private static OnItemClickListener onItemClickListener;
private Integer imageCount;
public ImageAdapter(String url, Integer imageCount, OnItemClickListener itemListener) {
this.ROOTURL = url;
this.imageCount = imageCount;
this.onItemClickListener = itemListener;
}
@Override
public int getItemCount() {
return imageCount;
}
@Override
public ImagesViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
this.mContext = parent.getContext();
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.images_viewitem, parent, false);
ImagesViewHolder imagesViewHolder = new ImagesViewHolder(v);
return imagesViewHolder;
}
@Override
public void onBindViewHolder(final ImagesViewHolder holder, int position) {
Glide.with(mContext)
.load("URL")
.asBitmap()
.centerCrop()
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.into(new BitmapImageViewTarget(holder.image) {
@Override
public void onLoadFailed(Exception e, Drawable errorDrawable) {
super.onLoadFailed(e, errorDrawable);
Log.e(IMAGES_FRAGMENT_TAG, "on load failed");
}
@Override
public void onResourceReady(Bitmap bitmap, GlideAnimation<? super Bitmap> glideAnimation) {
super.onResourceReady(bitmap, glideAnimation);
holder.image.setImageBitmap(bitmap);
}
});
}
public interface OnItemClickListener {
void onItemClick(View view, int position);
}
public static class ImagesViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private static final int PALETTE_SIZE = 24;
CardView cv;
ImageView image;
RelativeLayout mImageViewWrapper;
ImagesViewHolder(View itemView) {
super(itemView);
cv = (CardView) itemView.findViewById(R.id.imagesCardView);
image = (ImageView) itemView.findViewById(R.id.images_ImageView);
mImageViewWrapper = (RelativeLayout) itemView.findViewById(R.id.Images_imageViewWrapper);
itemView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
onItemClickListener.onItemClick(v, this.getLayoutPosition());
}
}
}
答案 0 :(得分:1)
您的问题出现在Fragment
:
protected static ImageAdapter mAdapter;
此行Adapter
:
private static OnItemClickListener onItemClickListener;
从不使用static
作为变量。除非你真的知道自己在做什么,否则不要这样做。 static
关键字导致ImageAdapter
和OnClickListener
在垃圾收集后Fragment
停留。这意味着变量mAdapter
不是Fragment
的任何实例的一部分,而是类本身的一部分 - 这当然是瞬间内存泄漏!删除那些,你应该没事。
顺便说一下,你可以很快就自己想出来。再看看LeakCanary输出:
它表示onItemClickListener
中的静态变量ImageAdapter
泄漏了ImagesFragment
个实例 - 换句话说就是我在这个答案中告诉你的内容。
另外,您应该阅读this answer以了解有关内存泄漏的更多信息。