Android如何高效地将可绘制图像加载到imageview
我需要将drawable文件夹中的一组图像加载到imageview列表中。我得到了一个java.lang.OutOfMemoryError:分配17280012字节分配失败,有8452164个空闲字节和8MB,直到OOM错误 下面是一个数组文件,其中列出了可绘制文件夹中需要加载的所有图像名称Android如何高效地将可绘制图像加载到imageview,android,performance,android-imageview,android-drawable,Android,Performance,Android Imageview,Android Drawable,我需要将drawable文件夹中的一组图像加载到imageview列表中。我得到了一个java.lang.OutOfMemoryError:分配17280012字节分配失败,有8452164个空闲字节和8MB,直到OOM错误 下面是一个数组文件,其中列出了可绘制文件夹中需要加载的所有图像名称 <?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="photo_frames"&g
<?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>
如果我有一些图片,它加载的很好,但是有点滞后。当有更多图像要加载到imageView时,它会返回一个错误,谢谢。17280012字节相当于2078 x 2078像素的图像这比大多数设备屏幕的分辨率都高。您应该一次加载0-1个图像,而不是12个图像 如果您的图像具有那样的高分辨率,请降低其分辨率
如果您的图像分辨率已经较低,但您将其置于
res/drawable/
中,请将其移动到res/drawable nodpi/
或计划为不同密度创建不同版本的可绘制图像。没有位图属于res/drawable/
,因为这只是res/drawable mdpi/
的同义词,因此Android将在密度更高的屏幕上对图像重新采样。17280012字节相当于2078 x 2078像素图像这比大多数设备屏幕的分辨率都高。您应该一次加载0-1个图像,而不是12个图像
如果您的图像具有那样的高分辨率,请降低其分辨率
如果您的图像分辨率已经较低,但您将其置于
res/drawable/
中,请将其移动到res/drawable nodpi/
或计划为不同密度创建不同版本的可绘制图像。没有位图属于res/drawable/
,因为这只是res/drawable mdpi/
的同义词,所以Android将在高密度屏幕上对图像进行重采样。这取决于图像的大小,当您在计算机上读取图像大小时,Android似乎会分配比图像大小多一点的空间。所以
- 你可以用小一点的图像
- 谷歌实际上已经发布了一个避免OutOfMemory错误的指南 这将帮助很多,虽然我不得不使用较小的图像大小 还有
- 一种几乎肯定有效的方法是设置 在清单中,在应用程序之间 标签。这将增加你的堆大小,但可能会使你的应用程序滞后 很少
- 您可以尝试使用Glide,谷歌推荐的库来加载图像
也许对你来说,这些想法的结合会起作用。这取决于你的图像有多大,当你在电脑上读取图像大小时,Android似乎会分配比图像大小多一点的空间。所以
- 你可以用小一点的图像
- 谷歌实际上已经发布了一个避免OutOfMemory错误的指南 这将帮助很多,虽然我不得不使用较小的图像大小 还有
- 一种几乎肯定有效的方法是设置 在清单中,在应用程序之间 标签。这将增加你的堆大小,但可能会使你的应用程序滞后 很少
- 您可以尝试使用Glide,谷歌推荐的库来加载图像
也许对你来说,这些想法的结合会起作用。你也可以使用缓存机制 下面的一个示例可能会让您了解如何使用图像缓存:
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);
}
}
}
公共类FlowerAdapter扩展了ArrayAdapter{
私人语境;
私人名册;
//将LRU(最近使用最少的)对象设置为图像缓存
专用LruCache图像缓存;
公共适配器(上下文、int资源、列表对象){
超级(上下文、资源、对象);
this.context=上下文;
this.flowerList=对象;
//初始化构造函数中的缓存
//确定设备的最大内存量
final int maxMemory=(int)(Runtime.getRuntime().maxMemory());
//将缓存大小设置为最大内存的八分之一
//final int cacheSize=maxMemory/9999999;//使用此数字可以看到效果
final int cacheSize=maxMemory/8;//实际情况
//创建映像缓存(实例化它)
imageCache=新的LruCache(缓存大小);
}
@凌驾
公共视图getView(int位置、视图转换视图、视图组父视图){
排气充气机
(LayoutInflater)context.getSystemService(Activity.LAYOUT\u flater\u SERVICE);
视图=充气机。充气(R.layout.item_-flower,父项,false);
//在TextView小部件中显示花朵名称
花卉=花卉列表。获取(位置);
TextView tv=(TextView)view.findViewById(R.id.textView1);
tv.setText(flower.getName());
//在ImageView小部件中显示花朵照片
//验证缓存中是否存在花
位图Bitmap=imageCache.get(flower.getProductId());
if(位图!=null){
ImageView image=(ImageView)view.findViewById(R.id.imageView1);
setImageBitmap(位图);
}
否则{
FlowerAndView容器=新建FlowerAndView();
容器。花=花;
container.view=视图;
ImageLoader=新的ImageLoader();
执行(容器);
}
返回视图;
}
类和视图{
公共花卉;
公众观点;
公共位图;
}
私有类ImageLoader扩展了异步任务{
@凌驾
受保护的花卉和视图背景(花卉和视图…参数){
FlowerAndView容器=参数[0];
花=容器。花;
试一试{
字符串imageUrl=MainActivity.PHOTOS\u BASE\u URL+flower.getPhoto();
InputStream in=(InputStream)新URL(imageUrl)。
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);
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer-array name="photo_frames">
<item>@drawable/pf1</item>
<item>@drawable/pf2</item>
.....
</integer-array>
</resources>
// 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();