Android ListView-图像在滚动时洗牌
我有一个包含两个文本视图和一个图像视图的列表视图。图像从Internet加载,并由LruCache缓存。当在ListView中滚动时,图像会被洗牌几秒钟。在正确的图像完全加载之前,不应该有任何图像。我发现了几个同样问题的问题,但没有人帮我:/。这是我的密码:Android ListView-图像在滚动时洗牌,android,listview,asynchronous,imageview,Android,Listview,Asynchronous,Imageview,我有一个包含两个文本视图和一个图像视图的列表视图。图像从Internet加载,并由LruCache缓存。当在ListView中滚动时,图像会被洗牌几秒钟。在正确的图像完全加载之前,不应该有任何图像。我发现了几个同样问题的问题,但没有人帮我:/。这是我的密码: public class NewsAdapter extends BaseAdapter { private static LayoutInflater inflater; private List<Item>
public class NewsAdapter extends BaseAdapter {
private static LayoutInflater inflater;
private List<Item> items = new LinkedList<Item>();
private LruCache<String, Bitmap> mMemoryCache;
public NewsAdapter(Context context) {
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// Bitmap Cache
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
final int cacheSize = maxMemory / 8;
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return getSizeInBytes(bitmap) / 1024;
}
};
}
public void add(Item item) {
items.add(item);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = new ViewHolder();
if(convertView == null) {
convertView = inflater.inflate(R.layout.list_item_item, null);
viewHolder.ivPic = (ImageView) convertView.findViewById(R.id.ivPic);
viewHolder.tvTitle = (TextView) convertView.findViewById(R.id.tvTitle);
viewHolder.tvShortDesc = (TextView) convertView.findViewById(R.id.tvShortDesc);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
final Item item = items.get(position);
viewHolder.tvTitle.setText(item.getTitle());
viewHolder.tvShortDesc.setText(Html.fromHtml(item.getShortDesc()));
Bitmap bitmap = mMemoryCache.get(item.getPicUrl());
if (bitmap != null) {
viewHolder.ivPic.setImageBitmap(bitmap);
} else {
GetBitmap gb = new GetBitmap(item.getPicUrl(), viewHolder.ivPic);
gb.execute();
}
return convertView;
}
static class ViewHolder {
ImageView ivPic;
TextView tvTitle;
TextView tvShortDesc;
}
@Override
public int getCount() {
return items.size();
}
@Override
public Item getItem(int position) {
return items.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@SuppressLint("NewApi")
public static int getSizeInBytes(Bitmap bitmap) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
return bitmap.getByteCount();
} else {
return bitmap.getRowBytes() * bitmap.getHeight();
}
}
private class GetBitmap extends AsyncTask<Void, Bitmap, Bitmap> {
private String url;
private ImageView ivPic;
public GetBitmap(String url, ImageView ivPic) {
this.url = url;
this.ivPic = ivPic;
}
@Override
protected Bitmap doInBackground(Void... params) {
Bitmap bitmap = null;
try {
URL url = new URL(this.url);
bitmap = BitmapFactory.decodeStream(url.openConnection().getInputStream());
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
if (bitmap != null) ivPic.setImageBitmap(bitmap);
}
}
}
公共类NewsAdapter扩展了BaseAdapter{
私人静电充气机;
私有列表项=新建LinkedList();
私人LruCache-mMemoryCache;
公共新闻适配器(上下文){
充气器=(LayoutFlater)context.getSystemService(context.LAYOUT\u充气器\u服务);
//位图缓存
final int maxMemory=(int)(Runtime.getRuntime().maxMemory()/1024);
最终int cacheSize=maxMemory/8;
mMemoryCache=新的LruCache(缓存大小){
@凌驾
受保护的int-sizeOf(字符串键、位图){
返回getSizeInBytes(位图)/1024;
}
};
}
公共作废添加(项目){
项目。添加(项目);
}
@凌驾
公共视图getView(int位置、视图转换视图、视图组父视图){
ViewHolder ViewHolder=新ViewHolder();
if(convertView==null){
convertView=充气机。充气(R.layout.list\u item\u item,null);
viewHolder.ivPic=(ImageView)convertView.findViewById(R.id.ivPic);
viewHolder.tvTitle=(TextView)convertView.findViewById(R.id.tvTitle);
viewHolder.tvShortDesc=(TextView)convertView.findViewById(R.id.tvShortDesc);
convertView.setTag(viewHolder);
}否则{
viewHolder=(viewHolder)convertView.getTag();
}
最终项目=项目。获取(位置);
viewHolder.tvTitle.setText(item.getTitle());
viewHolder.tvShortDesc.setText(Html.fromHtml(item.getShortDesc());
位图Bitmap=mMemoryCache.get(item.getPicUrl());
if(位图!=null){
viewHolder.ivPic.setImageBitmap(位图);
}否则{
GetBitmap gb=新的GetBitmap(item.getPicUrl(),viewHolder.ivPic);
gb.execute();
}
返回视图;
}
静态类视窗夹{
ImageView-ivPic;
文本视图标题;
文本视图tvShortDesc;
}
@凌驾
public int getCount(){
返回items.size();
}
@凌驾
公共项getItem(int位置){
返回项目。获取(位置);
}
@凌驾
公共长getItemId(int位置){
返回0;
}
@SuppressLint(“新API”)
公共静态整型getSizeInBytes(位图){
if(Build.VERSION.SDK\u INT>=Build.VERSION\u code.HONEYCOMB){
返回bitmap.getByteCount();
}否则{
返回bitmap.getRowBytes()*bitmap.getHeight();
}
}
私有类GetBitmap扩展异步任务{
私有字符串url;
私有ImageView ivPic;
公共GetBitmap(字符串url,ImageView ivPic){
this.url=url;
this.ivPic=ivPic;
}
@凌驾
受保护位图doInBackground(无效…参数){
位图=空;
试一试{
URL=新URL(this.URL);
位图=BitmapFactory.decodeStream(url.openConnection().getInputStream());
}捕获(例外e){
e、 printStackTrace();
}
返回位图;
}
@凌驾
受保护的void onPostExecute(位图){
onPostExecute(位图);
如果(位图!=null)ivPic.setImageBitmap(位图);
}
}
}
如果有人有主意就好了。。。提前谢谢
注:我忘了一些东西,请不要建议使用任何库,我想在没有任何外部库的情况下使用。可能就是这个代码片段
ViewHolder viewHolder = new ViewHolder();
也就是说,每次调用getView时,都会创建一个新的viewHolder实例
请尝试以下方法:
final ViewHolder viewHolder;
然后在if结构中
viewHolder = new ViewHolder();
在您的代码中实现:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
if(convertView == null) {
convertView = inflater.inflate(R.layout.list_item_item, null);
viewHolder = new ViewHolder();
viewHolder.ivPic = (ImageView) convertView.findViewById(R.id.ivPic);
viewHolder.tvTitle = (TextView) convertView.findViewById(R.id.tvTitle);
viewHolder.tvShortDesc = (TextView) convertView.findViewById(R.id.tvShortDesc);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
final Item item = items.get(position);
viewHolder.tvTitle.setText(item.getTitle());
viewHolder.tvShortDesc.setText(Html.fromHtml(item.getShortDesc()));
Bitmap bitmap = mMemoryCache.get(item.getPicUrl());
if (bitmap != null) {
viewHolder.ivPic.setImageBitmap(bitmap);
} else {
GetBitmap gb = new GetBitmap(item.getPicUrl(), viewHolder.ivPic);
gb.execute();
}
return convertView;
}
问题是您没有检查图像是否处于相同位置。请尝试上面的代码,希望对您有所帮助 这与视图回收和图像放置在错误的位置有关。看看这里,尝试删除final-here:final-Item=items.get(position);你需要在箱子里放一个占位符图像(位图==null)@tyczj好的,我会调查的。@LIlya Demidov我认为这样做不行。谢谢,你说得对,你的解决方案更好。但这不是问题所在。这个问题也发生在我实现整个ViewHolder之前。每次调用getView时都创建一个新的ViewHolder实例是对内存的浪费非常好!如果我滚动很快,仍然有一个错误的图像在半秒左右,但它比以前好多了!完美的非常感谢你!现在一切都正常了:)。我真的不明白(整数)getTag。。。。这里有什么?它不应该与像iv.getTag()这样的ImageView关联吗?@Vidor是的,它是针对图像的视图标记,需要加载。
public GetBitmap(String url, ImageView ivPic, int position) {
this.url = url;
this.ivPic = ivPic;
this.position = position;
ivPic.setTag(position);
ivPic.setImageBitmap(null);
}
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
if(bitmap != null && ((Integer)getTag) == this.position)
ivPic.setImageBitmap(bitmap);
}