Android如何有效地将可绘制图像加载到imageview

时间:2017-09-11 13:43:15

标签: android performance android-imageview android-drawable

我需要将drawable文件夹中的一堆图像加载到imageview列表中。我得到一个java.lang.OutOfMemoryError:无法分配17280012字节分配8452164个空闲字节和8MB直到OOM错误。

这是一个数组文件,列出了需要加载的drawable文件夹中的所有图像名称。

 <?xml version="1.0" encoding="utf-8"?>
 <resources>
<string-array name="photo_frames">
    <item>pf1</item>
    <item>pf2</item>
    <item>pf3</item>
    <item>pf4</item>
    <item>pf5</item>
    <item>pf6</item>
    <item>pf7</item>
    <item>pf8</item>
    <item>pf9</item>
    <item>pf10</item>
    <item>pf11</item>
    <item>pf12</item>
     </string-array>
 </resources>

这是listAdapter加载图片的代码,photoFrames是一个包含图片名称的数组。

public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        //Layout inflate for list item
        convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item_photo_frames, null);
    }

    ImageView imgPhotoFrames = (ImageView) convertView.findViewById(R.id.image_photo_frames);
    imgPhotoFrames.setImageResource(mContext.getResources().getIdentifier(photoFrames[position], "drawable", mContext.getPackageName()));


    return convertView;
}

如果我有一些图像,它可以很好地加载,但它有点滞后。当有更多图像要加载到imageView时,它会返回错误,谢谢。

4 个答案:

答案 0 :(得分:4)

17280012字节相当于2078 x 2078像素图像。 这大于大多数设备屏幕的分辨率。您应该一次加载0到1张这些图像,而不是12张。

如果您的图像具有这样的高分辨率,请降低其分辨率。

如果您的图片已经具有较低的分辨率,但是您将它们放在res/drawable/中,请将它们移至res/drawable-nodpi/或计划为不同的密度创建不同版本的drawable。 res/drawable/中没有位图,因为它只是res/drawable-mdpi/的同义词,因此Android会在更高密度的屏幕上对图像进行重新取样。

答案 1 :(得分:2)

你可以使用一个id的数组用于drawables

TypedArray

要加载它们,您可以使用// load array into CONSTRUCTOR TypedArray photoFrameArray = getResources().obtainTypedArray(R.array.photo_frames); // or set you ImageView's resource to the id imgPhotoFrames.setImageResource(photoFrameArray.getResourceId(position, R.drawable.default_drawable));

photoFrameArray.recycle();

请记住,您应该回收数组

Picasso

此外,如果您的图像非常大(1000x1000像素),则会出现内存问题

为了加载大图片,我建议您使用ImageView。您可以将大型drawable加载到cordova build -d

答案 2 :(得分:0)

这取决于您的Imageis有多大,当您在计算机上阅读尺寸时,Android似乎会分配比图像大小更多的空间。所以......

  • 您可以使用较小的图片。
  • Google实际上发布了一个避免OutOfMemoryErrors的指南 虽然我不得不使用较小的图像尺寸,但here会有很大的帮助 同样。
  • 几乎可以肯定的一种方法是设置 您的清单中的android:largeHeap="true",在您的申请之间 标签。这会增加您的堆大小,但可能会使您的应用程序滞后 小。
  • 您可以尝试使用Glide,谷歌推荐的lib来加载图片

也许对你而言,这些想法的组合将起作用。

答案 3 :(得分:0)

您也可以使用缓存机制。

这是一个可以让您了解使用图片缓存的示例:

public class FlowerAdapter extends ArrayAdapter<Flower> {

    private Context context;
    private List<Flower> flowerList;

    //set the LRU (Least Recently Used) object as an image cache
    private LruCache<Integer,Bitmap> imageCache;

    public FlowerAdapter(Context context, int resource, List<Flower> objects) {
        super(context, resource, objects);
        this.context = context;
        this.flowerList = objects;

        //initialize the cache in the constructor
        //determine the maximum amount of memory of the device
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory());
        //set the cache size to be one-eight of the maximum memory
//      final int cacheSize = maxMemory/9999999; //using this number you can see the effects
        final int cacheSize = maxMemory/8; //real-life situation
        //create the image cache (instantiate it)
        imageCache = new LruCache<>(cacheSize);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        LayoutInflater inflater = 
                (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        View view = inflater.inflate(R.layout.item_flower, parent, false);

        //Display flower name in the TextView widget
        Flower flower = flowerList.get(position);
        TextView tv = (TextView) view.findViewById(R.id.textView1);
        tv.setText(flower.getName());

        //Display flower photo in ImageView widget
        //verify if the flower exists in cache
        Bitmap bitmap = imageCache.get(flower.getProductId());
        if (bitmap != null) {
            ImageView image = (ImageView) view.findViewById(R.id.imageView1);
            image.setImageBitmap(bitmap);
        }
        else {
            FlowerAndView container = new FlowerAndView();
            container.flower = flower;
            container.view = view;

            ImageLoader loader = new ImageLoader();
            loader.execute(container);
        }


        return view;
    }

    class FlowerAndView {
        public Flower flower;
        public View view;
        public Bitmap bitmap;
    }

    private class ImageLoader extends AsyncTask<FlowerAndView, Void, FlowerAndView> {

        @Override
        protected FlowerAndView doInBackground(FlowerAndView... params) {

            FlowerAndView container = params[0];
            Flower flower = container.flower;

            try {
                String imageUrl = MainActivity.PHOTOS_BASE_URL + flower.getPhoto();
                InputStream in = (InputStream) new URL(imageUrl).getContent();
                Bitmap bitmap = BitmapFactory.decodeStream(in);
                flower.setBitmap(bitmap);
                in.close();
                container.bitmap = bitmap;
                return container;
            } catch (Exception e) {
                e.printStackTrace();
            }

            return null;
        }

        @Override
        protected void onPostExecute(FlowerAndView result) {
            ImageView image = (ImageView) result.view.findViewById(R.id.imageView1);
            image.setImageBitmap(result.bitmap);
//          result.flower.setBitmap(result.bitmap);
            //put the image in the cache
            imageCache.put(result.flower.getProductId(),result.bitmap);
        }

    }

}