【问题标题】:Android how to load drawable images to imageview efficientlyAndroid如何有效地将可绘制图像加载到imageview
【发布时间】:2017-09-11 13:43:15
【问题描述】:

我需要将可绘制文件夹上的一堆图像加载到 imageview 列表中。我收到 java.lang.OutOfMemoryError: Failed to allocate a 17280012 byte allocation with 8452164 free bytes and 8MB until OOM error.

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

 <?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 时,它会返回错误,谢谢。

【问题讨论】:

  • 使用 picasso、glide 等图片加载库
  • 尝试使用 RecyclerView 并使用诸如Glide 之类的第三方库来加载图像。

标签: android performance android-imageview android-drawable


【解决方案1】:

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

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

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

【讨论】:

【解决方案2】:

您可以将一组 id 用于可绘制对象

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <integer-array name="photo_frames">
        <item>@drawable/pf1</item>
        <item>@drawable/pf2</item>
        .....
    </integer-array>
</resources>

要加载它们,您可以使用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();

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

为了加载大图,我推荐你使用Picasso。您可以将大型绘图加载到您的ImageView

【讨论】:

    【解决方案3】:

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

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

    也许对你来说,这些想法的组合会奏效。

    【讨论】:

      【解决方案4】:

      您也可以使用缓存机制。

      这里有一个例子可能会让您对使用图像缓存有所了解:

      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);
              }
      
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-07-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-31
        相关资源
        最近更新 更多