ListView图片错乱

转自郭霖


错乱的原因

那么这里我们就可以思考一下了,目前数据源当中大概有60个图片的URL地址,而根据ListView的工作原理,显然不可能为每张图片都单独分配一个ImageView控件,ImageView控件的个数其实就比一屏能显示的图片数量稍微多一点而已,移出屏幕的ImageView控件会进入到RecycleBin当中,而新进入屏幕的元素则会从RecycleBin中获取ImageView控件。

那么,每当有新的元素进入界面时就会回调getView()方法,而在getView()方法中会开启异步请求从网络上获取图片,注意网络操作都是比较耗时的,也就是说当我们快速滑动ListView的时候就很有可能出现这样一种情况,某一个位置上的元素进入屏幕后开始从网络上请求图片,但是还没等图片下载完成,它就又被移出了屏幕。这种情况下会产生什么样的现象呢?根据ListView的工作原理,被移出屏幕的控件将会很快被新进入屏幕的元素重新利用起来,而如果在这个时候刚好前面发起的图片请求有了响应,就会将刚才位置上的图片显示到当前位置上,因为虽然它们位置不同,但都是共用的同一个ImageView实例,这样就出现了图片乱序的情况。

但是还没完,新进入屏幕的元素它也会发起一条网络请求来获取当前位置的图片,等到图片下载完的时候会设置到同样的ImageView上面,因此就会出现先显示一张图片,然后又变成了另外一张图片的情况,那么刚才我们看到的图片会自动变来变去的情况也就得到了解释。



activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    </ListView>

</LinearLayout>

image_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ImageView
        android:id="@+id/image"
        android:layout_width="match_parent"
        android:layout_height="120dp"
        android:src="@drawable/ic_launcher" 
        android:scaleType="fitXY"/>

</LinearLayout>

MainActivity

package com.example.listviewyouhua;

import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;

public class MainActivity extends Activity {
	
	private ListView listView;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		listView = (ListView) findViewById(R.id.list_view);
		ImageAdapter adapter = new ImageAdapter(this, 0, Images.imageUrls);
		listView.setAdapter(adapter);
	}


}

ImageAdapter

package com.example.listviewyouhua;

import java.net.HttpURLConnection;
import java.net.URL;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.os.AsyncTask;
import android.support.v4.util.LruCache;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;

public class ImageAdapter extends ArrayAdapter<String> {

	/**
	 * 图片缓存技术的核心类,用于缓存所有下载好的图片,在程序内存达到设定值时会将最少最近使用的图片移除掉。
	 */
	private LruCache<String, BitmapDrawable> mMemoryCache;

	/**
	 * 构造方法:获取图片缓存的大小内存
	 * 
	 * @param context
	 * @param resource
	 * @param objects
	 */
	public ImageAdapter(Context context, int resource, String[] objects) {
		super(context, resource, objects);
		// 获取应用程序最大可用内存
		int maxMemory = (int) Runtime.getRuntime().maxMemory();
		int cacheSize = maxMemory / 8;
		mMemoryCache = new LruCache<String, BitmapDrawable>(cacheSize) {
			@Override
			protected int sizeOf(String key, BitmapDrawable drawable) {
				return drawable.getBitmap().getByteCount();
			}
		};
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		String url = getItem(position);
		View view;
		if (convertView == null) {
			view = LayoutInflater.from(getContext()).inflate(
					R.layout.image_item, null);
		} else {
			view = convertView;
		}
		ImageView image = (ImageView) view.findViewById(R.id.image);
		BitmapDrawable drawable = getBitmapFromMemoryCache(url);
		if (drawable != null) {
			image.setImageDrawable(drawable);
		} else {
			BitmapWorkerTask task = new BitmapWorkerTask(image);
			task.execute(url);
		}
		return view;
	}

	/**
	 * 将一张图片存储到LruCache中。
	 * 
	 * @param key
	 *            LruCache的键,这里传入图片的URL地址。
	 * @param drawable
	 *            LruCache的值,这里传入从网络上下载的BitmapDrawable对象。
	 */
	public void addBitmapToMemoryCache(String key, BitmapDrawable drawable) {
		if (getBitmapFromMemoryCache(key) == null) {
			mMemoryCache.put(key, drawable);
		}
	}

	/**
	 * 从LruCache中获取一张图片,如果不存在就返回null。
	 * 
	 * @param key
	 *            LruCache的键,这里传入图片的URL地址。
	 * @return 对应传入键的BitmapDrawable对象,或者null。
	 */
	public BitmapDrawable getBitmapFromMemoryCache(String key) {
		return mMemoryCache.get(key);
	}

	/**
	 * 异步下载图片的任务。
	 * 
	 * @author guolin
	 */
	class BitmapWorkerTask extends AsyncTask<String, Void, BitmapDrawable> {

		private ImageView mImageView;

		public BitmapWorkerTask(ImageView imageView) {
			mImageView = imageView;
		}

		@Override
		protected BitmapDrawable doInBackground(String... params) {
			String imageUrl = params[0];
			// 在后台开始下载图片
			Bitmap bitmap = downloadBitmap(imageUrl);
			BitmapDrawable drawable = new BitmapDrawable(getContext()
					.getResources(), bitmap);
			/***将一张图片存储到LruCache中。*/
			addBitmapToMemoryCache(imageUrl, drawable);
			return drawable;
		}

		/**
		 * 下载图片完毕后,填充到控件中即可
		 */
		@Override
		protected void onPostExecute(BitmapDrawable drawable) {
			if (mImageView != null && drawable != null) {
				mImageView.setImageDrawable(drawable);
			}
		}

		/**
		 * 建立HTTP请求,并获取Bitmap对象。
		 * 
		 * @param imageUrl
		 *            图片的URL地址
		 * @return 解析后的Bitmap对象
		 */
		private Bitmap downloadBitmap(String imageUrl) {
			Bitmap bitmap = null;
			HttpURLConnection con = null;
			try {
				URL url = new URL(imageUrl);
				con = (HttpURLConnection) url.openConnection();
				con.setConnectTimeout(5 * 1000);
				con.setReadTimeout(10 * 1000);
				bitmap = BitmapFactory.decodeStream(con.getInputStream());
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				if (con != null) {
					con.disconnect();
				}
			}
			return bitmap;
		}

	}

}

Images

package com.example.listviewyouhua;
public class Images {

    public final static String[] imageUrls = new String[] {
    	"http://img.my.csdn.net/uploads/201508/05/1438760758_3497.jpg",  
        "http://img.my.csdn.net/uploads/201508/05/1438760758_6667.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760757_3588.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760756_3304.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760755_6715.jpeg",
        "http://img.my.csdn.net/uploads/201508/05/1438760726_5120.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760726_8364.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760725_4031.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760724_9463.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760724_2371.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760707_4653.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760706_6864.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760706_9279.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760704_2341.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760704_5707.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760685_5091.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760685_4444.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760684_8827.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760683_3691.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760683_7315.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760663_7318.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760662_3454.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760662_5113.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760661_3305.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760661_7416.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760589_2946.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760589_1100.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760588_8297.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760587_2575.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760587_8906.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760550_2875.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760550_9517.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760549_7093.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760549_1352.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760548_2780.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760531_1776.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760531_1380.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760530_4944.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760530_5750.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760529_3289.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760500_7871.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760500_6063.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760499_6304.jpeg",
        "http://img.my.csdn.net/uploads/201508/05/1438760499_5081.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760498_7007.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760478_3128.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760478_6766.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760477_1358.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760477_3540.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760476_1240.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760446_7993.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760446_3641.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760445_3283.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760444_8623.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760444_6822.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760422_2224.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760421_2824.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760420_2660.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760420_7188.jpg",
        "http://img.my.csdn.net/uploads/201508/05/1438760419_4123.jpg",
    };
}


你可能感兴趣的:(ListView图片错乱)