我正在进行一项带有列表视图的活动。列表视图由从服务器提取的大型 XML 填充。我的场景通常是有一个 SAX 解析器,解析 XML 并返回带有解析数据的向量(或类似结构)。问题是 xml 太大并且 Vector 有太多元素导致内存不足错误。此外,xml 还包含指向正在下载的图像的链接,这使情况变得更糟。
在这种情况下我应该如何管理内存?我在想是否可以仅在用户滚动到列表视图中的给定行时才加载图像。
我正在进行一项带有列表视图的活动。列表视图由从服务器提取的大型 XML 填充。我的场景通常是有一个 SAX 解析器,解析 XML 并返回带有解析数据的向量(或类似结构)。问题是 xml 太大并且 Vector 有太多元素导致内存不足错误。此外,xml 还包含指向正在下载的图像的链接,这使情况变得更糟。
在这种情况下我应该如何管理内存?我在想是否可以仅在用户滚动到列表视图中的给定行时才加载图像。
内存不足异常的问题是图像的加载。将Adapter
自己填充到ListView
.
在一个业务应用程序中,我正在加载ListView
9000 条记录,TextView
每行 2 秒。所以我猜数据的大小应该不是问题。
使用 anAsyncTask
从服务器获取数据。在方法中解析并填充适配器,doInBackground()
然后onPostExecute()
在ListView
. 首先尝试不包含任何图像,以确保数据大小不是问题。
如果ListView
加载正确,则尝试找到填充图像的方法。执行此操作有多种方法。如果图像一遍又一遍地相同,您应该尝试“缓存在内存中”实现,否则后台线程的“延迟加载”可能会很好地完成这项工作。
编辑:
这是一篇关于如何从后台线程延迟加载图像的非常好的帖子/教程。当您查看 a 中的所有应用程序时,它“几乎”与 android 市场使用的技术相同GridView
,起初有一些灰色图标,然后突然出现应用程序的图像。这是从后台线程完成的,当用户可以看到确切的行时,后台线程从 Internet 获取它,填充列表并将其缓存在内存中,以便立即再次可用。ListView 中图像的延迟加载
用于service
将 XML 从服务器拉到database
. 您比在 Google Play 中看到的activity
延迟加载数据。database
请参阅CWAC EndlessAdapter。另请参阅
适用于 Android 的 Universal Image Loader以填充您listview
的图像。
OutOfMemoryException 很可能是由图像引起的。
假设您要显示带有图片的酒店列表。您以 XML 格式获取酒店信息并将它们保存在列表(或类似结构)中。您的酒店类可能有一个类似URL pictureURL
的成员WeakReference<Drawable> picture
,并且在需要之前,这样的成员将是空的。
您可以让列表适配器AsyncTask
在 getView() 方法中开始下载图像(如果图片指向 null)并将其设置为列表中的 ImageView 和Hotel.picture
.
因为 Hotel.picture 是一个弱引用,所以当图像离开屏幕时,内存将被释放,因为ImageViews
被回收
您的 getView 方法可能包含如下内容:
private class MyCustomAdapter extends BaseAdapter {
...
List<Hotel> hotelList;
...
@Override
public View getView(int position, View convertView, ViewGroup parent) {
...
Hotel hotel = hotelList.get(position);
ImageView ivHotelPic = //your image view from the list (child of 'view')
...
if (hotel.picture == null || hotel.picture.get() == null){
new DownloadImageTask(hotel,ivHotelPic).execute(hotel.pictureURL)
}
else{
ivHotelPic.setImageDrawable( hotel.picture.get() );
}
return view;
}
}
private class DownloadImageTask extends AsyncTask<URL, Integer, Drawable> {
Hotel hotel;
ImageView imageView;
DownloadImageTask(Hotel hotel,ImageView imageView){
this.hotel = hotel;
this.imageView = imageView;
}
protected Drawable doInBackground(URL... urls) {
assert urls.length == 1;
Drawable image = //download image from urls[0] (or hotel.pictureURL);
return image;
}
protected void onPostExecute(Drawable result) {
imageView.setImageDrawable(result);
hotel.picture = new WeakReference<Drawable>(result);
}
}
如果您想保留图像直到活动关闭,您也可以对图像使用常规引用,但是当下载的图像过多时,这可能会导致 OutOfMemory。