使用Picasso和Recycler View时出现内存不足问题

时间:2016-05-07 03:17:35

标签: android memory-management memory-leaks out-of-memory android-recyclerview

我收到此错误:

java.lang.OutOfMemoryError: Failed to allocate a 15052812 byte allocation with 12653776 free bytes and 12MB until OOM

这是我的适配器:

public class ExploreAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private List<Obj> exploreList;
    private Context context;
    private Typeface typeFace, italicTypeface, boldTypeface;
    private DatabaseHelper db;

    private Obj featureProject;
    private boolean exploreReturned50;



    public class MyViewHolder extends RecyclerView.ViewHolder {
        public TextView projectTitle;
        public ImageView projectPicture;


        public MyViewHolder(View view) {
            super(view);
            projectTitle = (TextView) view.findViewById(R.id.exploreProjectTitle);
             projectPicture = (ImageView) view.findViewById(R.id.exploreProjectPicture);

        }



    }

    private static OnGrabMoreListener mOnGrabMoreListener;

    public interface OnGrabMoreListener {
        void onGrabMore(int position);
    }


    public void setOnGrabMoreListener(OnGrabMoreListener onGrabMoreListener) {
        mOnGrabMoreListener = onGrabMoreListener;
    }

    public class MyFeatureViewHolder extends RecyclerView.ViewHolder {
        public TextView featureProjectTitle;
        public ImageView featureProjectImage;

        public MyFeatureViewHolder(View view) {
            super(view);

            featureProjectImage = (ImageView) view.findViewById(R.id.featureProjectImage);
            featureProjectTitle = (TextView) view.findViewById(R.id.featureProjectTitle);
           }


    }

    public ExploreAdapter(Context mContext, Obj featureProj, List<Obj> explores, Typeface myTypeface, Typeface myTypefaceItalic, Typeface myTypefaceBold) {
        context = mContext;
        exploreList = explores;
        typeFace = myTypeface;
        italicTypeface = myTypefaceItalic;
        boldTypeface = myTypefaceBold;
        //to set up grabmore
        if(exploreList.size() == 50 || exploreList.size() == 51) {
            exploreReturned50 = true;
        }
        db = new DatabaseHelper(mContext);
        featureProject = featureProj;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        switch (viewType){
            case 0:
                return new MyFeatureViewHolder(LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.feature_item, parent, false));  }
         return new MyViewHolder(LayoutInflater.from(parent.getContext())
                 .inflate(R.layout.explore_item, parent, false));


    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {


        int pos = getItemViewType(position);

        if(pos == 0) {

            MyFeatureViewHolder featureViewHolder = (MyFeatureViewHolder) holder;

           featureViewHolder.featureProjectTitle.setTypeface(boldTypeface);

            featureViewHolder.featureProjectTitle.setText(featureProject.getProjectTitle());


             String createImagePath = Constants.PROJECT_IMAGE + featureProject.getDefaultPicId();
            Picasso.with(context).load(createImagePath).placeholder(R.drawable.default_user).into(featureViewHolder.featureProjectImage);

        } else {

            MyViewHolder myViewHolder = (MyViewHolder) holder;
            Obj proj = exploreList.get(position);


            myViewHolder.projectTitle.setTypeface(boldTypeface);


            myViewHolder.projectTitle.setText(proj.getProjectTitle());


            String createImagePath = Constants.PROJECT_IMAGE + proj.getDefaultPicId();
            Picasso.with(context).load(createImagePath).placeholder(R.drawable.default_user).into(myViewHolder.projectPicture);

        }


            mOnGrabMoreListener.onGrabMore(position);
        if (position > (exploreList.size() - 20) && exploreReturned50) {
            grabMoreFromExplorer();
        }

    }

    private void grabMoreFromExplorer() {

        Log.d(Constants.DEBUG, "GRAB MORE");

        Call<List<ObjResp>> call = ApiManager.getAsyncApi().exploreProjects(exploreList.size());
            call.enqueue(new Callback<List<ObjResp>>() {
                @Override
                public void onResponse(Call<List<ObjResp>> call, Response<List<ObjResp>> response) {
                    storeInDbNewExplore(response);
                }

                @Override
                public void onFailure(Call<List<ObjResp>> call, Throwable t) {

                    Log.d(Constants.DEBUG, "There has been an error retrieving explores project " + t);
                }
            });

    }

    private void storeInDbNewExplore(Response<List<ObjResp>> response) {
        Log.d(Constants.DEBUG, "STORING explores ");
        List<ObjResp> projectsApi = response.body();

        for(ObjResp proj: projectsApi) {
            String projectId, projectTitle, defaultPicId, isType, isChanged;

            projectId = proj.get_id();
            projectTitle = proj.getTitle();
            defaultPicId = proj.getDefaultPicId();

            isType = 1;
            isChanged = 0;
            Obj newDbExploreProj = new Obj(projectId, projectTitle,  defaultPicId, isChanged, isType);

            db.createProject(newDbExploreProj);
        }
        //TODO sort explores by dateAdded
        List<Obj> newExploreList = db.getProjects(1, 0);
        exploreList.addAll(newExploreList);
    }


    //Plus one for feature project
    @Override
    public int getItemCount() {

      //  Log.d(Constants.DEBUG, "THE EXPLORE LIST SIZE IS "  + exploreList.size() );
        return exploreList.size();
    }


    @Override
    public int getItemViewType(int position) {
        return position;
    }

}

这是我的活动中的Recycler View Call:

exploreAdapter = new ExploreAdapter(this, featureProject, exploreProjectsList, TypeFaceProvider.getTypeFace(this, 0),
                TypeFaceProvider.getTypeFace(this, 1), TypeFaceProvider.getTypeFace(this, 2));
        GridLayoutManager mLayoutManager = new GridLayoutManager(this, 2);

        //used for setting spotlight item first
        mLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
            @Override
            public int getSpanSize(int position) {
                if(exploreAdapter.getItemViewType(position) == 0) {
                    return 2;
                } else {
                    return 1;
                }

            }
        });
        exploreRecyclerview.setLayoutManager(mLayoutManager);
        exploreRecyclerview.setItemAnimator(new DefaultItemAnimator());


        exploreRecyclerview.setAdapter(exploreAdapter);
        exploreRecyclerview.addOnItemTouchListener(new RecyclerClicks.RecyclerTouchListener(this, exploreRecyclerview, new RecyclerClicks.ClickListener() {
            @Override
            public void onClick(View view, int position) {
                DatabaseProject proj = exploreProjectsList.get(position);
                Toast.makeText(getApplicationContext(), proj.getProjectTitle() + " is selected!", Toast.LENGTH_SHORT).show();
                takeToProjectProfile(exploreProjectsList.get(position));
            }

            @Override
            public void onLongClick(View view, int position) {

            }
        }));


        exploreAdapter.notifyDataSetChanged();

2 个答案:

答案 0 :(得分:1)

CRASH:

正如您的stacktrace所说:

  

“java.lang.OutOfMemoryError:无法分配15052812字节   分配12653776个空闲字节和12MB直到OOM“

您尝试在视图上显示一个巨大的位图。你的手机不喜欢它。

两个解决方案:

  • 缩小图像的尺寸,使用较小的图像...和 重试<!/ LI> 在您的应用程序中
  • 或在您的清单中设置android:largeHeap="true" 标签。它会增加堆大小并避免 OutOfMemory 错误,但您的申请可能会滞后。

答案 1 :(得分:1)

如果有人遇到类似问题,请快速更新:用 COIL 替换 Picasso 像魔法一样解决了我在低容量智能手机中的 OOM 问题。就我而言,内存使用量下降了近 50%。这是链接仅供参考:https://github.com/coil-kt/coil

值得一提的是,我使用的是 Kotlin。 快乐编码! ;)