OutOfMemoryException:从服务器加载一堆图像

时间:2014-08-01 09:35:03

标签: android out-of-memory

我正在开发一个从Server API下载图像的应用程序...
我们创建了一个API,它提供了图像URL的JSON响应......

我创建GridView用于显示图片,但它正在成功运作....

但问题是,当图像数量增加时,由于堆内存增加,它会抛出OutOfMemoryException ...

我试图通过System.gc();手动清除堆内存..但没有效果.......

所以,我的问题是:如何在没有此问题的情况下从服务器成功加载所有图像.. 我应该做些什么改变来解决这个问题

有我的JSON和代码..

JSON:

{
is_error: "false",
is_error_msg: "Video/Image List",
images: [
     "http://equestsolutions.net/clients/elad/MovieApp/public/uploads/Screenshot_2014-07-21-17-22-43.png",
     "http://equestsolutions.net/clients/elad/MovieApp/public/uploads/IMG_20140521_155703.jpg",
     "http://equestsolutions.net/clients/elad/MovieApp/public/uploads/IMG_20140522_152254.jpg",
     "http://equestsolutions.net/clients/elad/MovieApp/public/uploads/1386231199182.jpg",
     "http://equestsolutions.net/clients/elad/MovieApp/public/uploads/DSC01809.JPG"
],
videos: [ ],
others: [ ]
}

ImageAdapter.java

private class ImageAdapter extends BaseAdapter {

    private final Context mContext;
    ArrayList<String> urls_list;
    ProgressBar pbrLoadImage;

    public ImageAdapter(Context context,ArrayList<String> urls_list) {
        super();
        mContext = context;
        this.urls_list= urls_list;
    }

    @Override
    public int getCount() {
        return urls_list.size();
    }

    @Override
    public Object getItem(int position) {
        return urls_list.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup container) {
        ImageView imageView;

        if (convertView == null) { // if it's not recycled, initialize some attributes
            LayoutInflater mInflater = (LayoutInflater)
                    getActivity().getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
            convertView = mInflater.inflate(R.layout.image_grid_fragment_raw, null);
        }
        FrameLayout frm = (FrameLayout)convertView.findViewById(R.id.imageframe);
        pbrLoadImage =(ProgressBar)convertView.findViewById(R.id.pbrLoadImage);
        imageView = (ImageView)convertView.findViewById(R.id.imageFromUrl); ImageView(mContext);
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        imageView.getLayoutParams().height = 160;
        imageView.getLayoutParams().width = 160;

        Log.i("values", "value :"+url_list.get(position));

        new BitmapWorkerTask(imageView).execute(url_list.get(position)); // calling class for download Images...
        return convertView;
    }

    //download Images from path
    class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {
        private final WeakReference<ImageView> imageViewReference;
        //private int data = 0;
        String path=null;
        Bitmap mIcon=null;

        public BitmapWorkerTask(ImageView imageView) {
            // Use a WeakReference to ensure the ImageView can be garbage collected
            imageViewReference = new WeakReference<ImageView>(imageView);
        }

        // Decode image in background.
        @Override
        protected Bitmap doInBackground(String... params) {
            //data = params[0];
            path = params[0];

            InputStream in=null;
            ByteArrayOutputStream out=null;
            try {
                in = new java.net.URL(path).openStream();
                mIcon = BitmapFactory.decodeStream(in);
                out= new ByteArrayOutputStream();
                mIcon.compress(Bitmap.CompressFormat.PNG, 100, out);
                in.close();
                out.close();

            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }


            //return decodeSampledBitmapFromResource(getResources(), data, 100, 100));
            //return BitmapFactory.decodeStream(new ByteArrayInputStream(out.toByteArray()));
            return mIcon;
        }

        // Once complete, see if ImageView is still around and set bitmap.
        @Override
        protected void onPostExecute(Bitmap bitmap) {

            if (imageViewReference != null && bitmap != null) {

                final ImageView imageView = imageViewReference.get();

                if (imageView != null) {
                    imageView.setImageBitmap(bitmap);
                }
            }
        }
    }
}

请告诉我应该采取哪些措施来解决我的问题..

提前感谢您的帮助......

3 个答案:

答案 0 :(得分:3)

这在android中是一个非常常见的问题。将位图加载到内存中可能会导致OutOfMemoryException

我建议您使用像picasso这样的lib,这个lib会在后台为您加载图像,并调整它们以使您的ImageView适合一行代码。

Picasso.with(context).load(URL).fit().centerCrop().into(imageView);

答案 1 :(得分:0)

在inPurgeable中添加BitmapFactory.Options也计算可能的最大inSampleSize 对于参考Check thisthis link

答案 2 :(得分:0)

  1. 我检查了您从服务器获取的浏览器上的图像,发现图像的分辨率非常高,大约为960 * 1280,而您正在使用135 * 160像素的GridView中的图像这样下载的位图与你需要的大小相比非常大,所以如果可能的话,既然你正在按照你的说法管理API,你可以将图像上传到最大尺寸的服务器上,因为那只是浪费网络带宽,因为必须获取更多数据,获取更多时间,并将更多内存保存在内存中。

  2. 使用最低API级别为11,因为位图存储在本机内存之前的API级别11,垃圾收集器无法进行垃圾收集,相反从API级别开始11位图存储在dalvik中(类似于Android虚拟机) Java虚拟机)堆内存,可以在垃圾收集器运行时进行垃圾回收。

  3. 调用bitmap.recycle();使用创建的位图后,使用这两行代码片段。  的System.gc();  调用Runtime.getRuntime()GC();

  4. 在使用任何流或数据库相关操作时要格外小心,因为如果流或数据库未正确关闭,则会导致难以捉摸的内存泄漏。

  5. 此外,我不知道为什么要使用输出流将PNG压缩图像保存到内部存储器:   out = new ByteArrayOutputStream();   mIcon.compress(Bitmap.CompressFormat.PNG,100,out);

  6. 使用android:largeHeap =&#34; true&#34;它不是解决内存问题的正确方法,只是延迟崩溃永远不会完全防止内存崩溃。