【问题标题】:Out of memory error when using picasso with recycler view将毕加索与回收站视图一起使用时出现内存不足错误
【发布时间】:2017-01-27 20:56:20
【问题描述】:

我想在滚动回收站视图时异步加载图像。为此,我使用 picasso 从 url 加载图像。此外,我正在为图像使用圆形图像视图。

现在,当我先向上和向下滚动时,加载图像需要 10 到 12 秒。当我滚动它时,它会在圆形图像视图上出现内存不足错误。

联系人适配器:

    public class ContactAdapter extends RecyclerView.Adapter<FeedListRowHolder> {


    private List<FeedItem> feedItemList;

    private Context mContext;

    public ContactAdapter(Context context, List<FeedItem> feedItemList) {
        this.feedItemList = feedItemList;
        this.mContext = context;
    }

    @Override
    public FeedListRowHolder onCreateViewHolder(ViewGroup viewGroup, int i) {

        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_layout,null);
        FeedListRowHolder mh = new FeedListRowHolder(v);

        return mh;
    }

    @Override
    public void onBindViewHolder(FeedListRowHolder feedListRowHolder, int i) {
        final FeedItem feedItem = feedItemList.get(i);
        Log.e("Imagename",""+"http://xesoftwares.co.in/contactsapi/profile_images/85368a5bbd6cffba8a3aa202a80563a2.jpg");//+feedItem.getThumbnail());
       /* Picasso.with(mContext).load("http://xesoftwares.co.in/contactsapi/profile_images/85368a5bbd6cffba8a3aa202a80563a2.jpg")
                .error(R.drawable.ic_account_circle_black_24dp)
                .placeholder(R.drawable.ic_account_circle_black_24dp)
                .into(feedListRowHolder.thumbnail)
                ;*/

       Picasso.with(mContext).load("http://xesoftwares.co.in/contactsapi/profile_images/85368a5bbd6cffba8a3aa202a80563a2.jpg")
                .error(R.drawable.ic_account_circle_black_24dp)
                .placeholder(R.drawable.ic_account_circle_black_24dp)
                .into(new Target() {

                    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                        try {
                            String root = Environment.getExternalStorageDirectory().getPath();
                            File myDir = new File(root +"/Contact");

                            if (!myDir.exists()) {
                                myDir.mkdirs();
                            }

                           // String name = new Date().toString();
                            String name = new Date().toString()+".jpg";
                          File  myDir1 = new File(myDir, name);

                            FileOutputStream out = new FileOutputStream(myDir1);
                            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);

                            ImageFilePath imageFilePath1=new ImageFilePath(myDir1);
                            ComplexPreferences complexPreferences112 = ComplexPreferences.getComplexPreferences(mContext, "mypref112", Context.MODE_PRIVATE);
                            complexPreferences112.putObject("imageFilePath1", imageFilePath1);
                            Log.e("user2", "" + imageFilePath1);
                            complexPreferences112.commit();
                            out.flush();
                            out.close();
                        } catch(Exception e){
                            // some action
                        }
                    }


                    public void onBitmapFailed(Drawable errorDrawable) {
                    }


                    public void onPrepareLoad(Drawable placeHolderDrawable) {
                    }
                });


       ComplexPreferences complexPreferences112 = ComplexPreferences.getComplexPreferences(mContext, "mypref112", mContext.MODE_PRIVATE);
        ImageFilePath imageFilePath1= complexPreferences112.getObject("imageFilePath1", ImageFilePath.class);
        File myDir1=imageFilePath1.getprofile();

       Picasso.with(mContext).load(myDir1).into(feedListRowHolder.thumbnail);

        feedListRowHolder.title.setText(Html.fromHtml(feedItem.getTitle()));
        //feedListRowHolder.genre.setText(Html.fromHtml(feedItem.getGenre()));

    }

    @Override
    public int getItemCount() {
        return (null != feedItemList ? feedItemList.size() : 0);
    }
}

roundedImageView :

   public  class RoundedImageView extends ImageView {
    public RoundedImageView(Context ctx, AttributeSet attrs) {
            super(ctx, attrs);
        }


        @Override
        protected void onDraw(Canvas canvas) {

            Drawable drawable = getDrawable();

            if (drawable == null) {
                return;
            }

            if (getWidth() == 0 || getHeight() == 0) {
                return;
            }
            Bitmap b =  ((BitmapDrawable)drawable).getBitmap() ;
           if(b!=null) {
            Bitmap bitmap = b.copy(Config.ARGB_4444, true); //error line 39                          

               int w = getWidth() / 2;


               Bitmap roundBitmap = getRoundedCroppedBitmap(bitmap, w);
               canvas.drawBitmap(roundBitmap, 0, 0, null);
           }

        }

        public static Bitmap getRoundedCroppedBitmap(Bitmap bitmap, int radius) {
            Bitmap finalBitmap;
            if(bitmap.getWidth() != radius || bitmap.getHeight() != radius)
                finalBitmap = Bitmap.createScaledBitmap(bitmap, radius, radius, false);
            else
                finalBitmap = bitmap;
            Bitmap output = Bitmap.createBitmap(finalBitmap.getWidth(),
                    finalBitmap.getHeight(), Config.ARGB_4444);
            Canvas canvas = new Canvas(output);

            final Paint paint = new Paint();
            final Rect rect = new Rect(0, 0, finalBitmap.getWidth(), finalBitmap.getHeight());

            paint.setAntiAlias(true);
            paint.setFilterBitmap(true);
            paint.setDither(true);
            canvas.drawARGB(0, 0, 0, 0);
            paint.setColor(Color.parseColor("#BAB399"));
            canvas.drawCircle(finalBitmap.getWidth() / 2+0.7f, finalBitmap.getHeight() / 2+0.7f,
                    finalBitmap.getWidth() / 2+0.1f, paint);
            paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
            canvas.drawBitmap(finalBitmap, rect, rect, paint);


            return output;
        }

}

错误:

       java.lang.OutOfMemoryError
                                                               at android.graphics.Bitmap.nativeCopy(Native Method)
                                                               at android.graphics.Bitmap.copy(Bitmap.java:556)
                                                               at com.xesc.contacts.utils.RoundedImageView.onDraw(RoundedImageView.java:39)

如何解决这个内存不足错误?我尝试在 picasso 中使用 .fit(),但它给出了非法状态异常。另外加载图像至少需要 10 秒,如何减少加载图像的时间?

谢谢你..

编辑:.into() 之后的代码不起作用,它直接跳转到 complexShared 首选项。并且由于复杂的 sharedPreferences 保持为空,它会引发空指针异常。

这发生在我卸载应用程序并再次运行时。在它运行良好之前。

【问题讨论】:

  • 您的图像尺寸必须比您为 ImageView 指定的尺寸大。在服务器上增加尺寸或减小图像的大小。
  • 调整大小怎么样?您是否尝试过毕加索的调整大小功能,如果没有,请尝试一下
  • 如何调整大小?你能展示一下吗? @乔治·托马斯
  • 只需在您的毕加索调用中添加 .resize(100,100) 即可。将 100 * 100 替换为您所需的图像尺寸。您还可以在 picasso 上调用 .onlyScaleDown() 来指示它仅在实际图像大小大于 resize 方法中指定的宽度和高度时才调整图像大小。这么小的图片不会被调整大小
  • .onlyScaleDown() 在毕加索中找不到。 @GeorgeThomas

标签: android out-of-memory picasso


【解决方案1】:

首先检查::如果下载的图像有大流会导致内存不足:所以首先这样做

           Picasso.with(mContext).load("http://xesoftwares.co.in                                   /contactsapi/profile_images/85368a5bbd6cffba8a3aa202a80563a2.jpg")
            .error(R.drawable.ic_account_circle_black_24dp)
            .placeholder(R.drawable.ic_account_circle_black_24dp)
             .resize(width, height) //you height width

下一个检查:: 压缩成位图 :: 将压缩放入 try catch 作为有风险的代码:让我知道它是否有帮助:)

编辑:为空指针执行此解决方案

  ImageFilePath imageFilePath1=new ImageFilePath(myDir1);

   ComplexPreferences complexPreferences112 = ComplexPreferences.getComplexPreferences(mContext, "mypref112", Context.MODE_PRIVATE);
           if(imageFilePath1!=null)
         complexPreferences112.putObject("imageFilePath1", imageFilePath1);

【讨论】:

  • 在我卸载应用程序并再次运行后,它没有运行 .into() 的代码。你能告诉我为什么会这样吗? @KanishR
  • 您能否详细说明:它没有像以下那样运行:执行未到达这一行或如果有任何异常出现异常请添加它... :::: 可能您的视图尚未准备好加载。 . 你能在它前面加上 .error 和 .placeholder
  • 当我从 sharedPreferences 中获取对象而不是将对象放入共享首选项时,它会给出空指针异常。 @KanishR
  • @Sid 您是否实现了上述代码检查图像路径1 是否为空?当您安装应用程序时,共享偏好在地图中有数据,共享偏好被删除..所以当您清除应用程序的数据时..我实际上并没有得到什么时候卡住,因为在编辑的问题中它不是空指针。请添加我编辑的答案的代码部分,让我们看看它是否有效
  • 问题是 onBitmapLoaded 方法没有得到执行。我试过你的解决方案不起作用。因为问题是方法没有得到执行。 @KanishR
【解决方案2】:

您的代码可能会将完整图像下载到内存中,在您不需要完整图像的内存中它可能更接近您的图像视图,

在 picaso fit() 处理程序中,它使用 BitmapFactory.Options 上的 inSampleSize 在图像加载到内存时对其进行下采样,但这取决于您的图像视图大小, 它可能对你有帮助。 你可能会像这样使用:

.fit().centerCrop()

【讨论】:

  • 在我卸载应用程序并再次运行后,它没有运行 .into() 的代码。你能告诉我为什么会这样吗? @Dhavalkumar Solanki
【解决方案3】:

查看您的代码,您没有回收位图,因此预计会出现 OutOfMemory 错误,一旦不使用它们,您需要回收所有位图,因此您必须保留对它们的引用。在这里查看更多关于回收位图的更深入见解:

Android: Bitmap recycle() how does it work?

在您的情况下,您的 ImageView 中的 onDraw() 函数创建了 2 个位图,一个带有副本,一个带有裁剪:

首先,你不需要创建位图,这里你有如何在不创建实际位图的情况下读取图像大小,所以如果图像很大你会崩溃:

android: get image dimensions without opening it

public static Bitmap lessResolution (String filePath, int width, int height) {
    int reqHeight = height;
    int reqWidth = width;
    BitmapFactory.Options options = new BitmapFactory.Options();    

    // First decode with inJustDecodeBounds=true to check dimensions
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(filePath, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;        

    return BitmapFactory.decodeFile(filePath, options); 
}

private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {

    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {
        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        // Choose the smallest ratio as inSampleSize value, this will guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }
    return inSampleSize;
}

在你加载较小的位图后,保留对它的引用,一旦不需要它就必须回收,所以你需要覆盖 onDetacheFromWindow 函数并在那里使用 bitmap.recycle()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-10
    • 2017-10-30
    • 2011-07-13
    • 2014-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-30
    相关资源
    最近更新 更多