在使用listview下载图片的时候,经常遇到图片错乱问题,快速滑动会导致图片位置不对,这里提供一种思路
实现效果图:
(1)activity_main.xml
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
(2)images_item.xml
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="120dp"
android:src="@mipmap/empty_photo"
android:scaleType="fitXY"/>
(3)在清单文件AndroidManifest.xml里添加联网权限
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
(4)创建一个图片类Images,用于放置图片数组
public class Images {
public final static String[] imageUrls = new String[] {
"https://img-my.csdn.net/uploads/201508/05/1438760758_3497.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760758_6667.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760757_3588.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760756_3304.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760755_6715.jpeg",
"https://img-my.csdn.net/uploads/201508/05/1438760726_5120.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760726_8364.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760725_4031.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760724_9463.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760724_2371.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760707_4653.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760706_6864.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760706_9279.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760704_2341.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760704_5707.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760685_5091.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760685_4444.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760684_8827.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760683_3691.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760683_7315.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760663_7318.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760662_3454.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760662_5113.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760661_3305.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760661_7416.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760589_2946.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760589_1100.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760588_8297.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760587_2575.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760587_8906.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760550_2875.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760550_9517.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760549_7093.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760549_1352.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760548_2780.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760531_1776.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760531_1380.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760530_4944.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760530_5750.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760529_3289.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760500_7871.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760500_6063.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760499_6304.jpeg",
"https://img-my.csdn.net/uploads/201508/05/1438760499_5081.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760498_7007.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760478_3128.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760478_6766.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760477_1358.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760477_3540.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760476_1240.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760446_7993.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760446_3641.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760445_3283.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760444_8623.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760444_6822.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760422_2224.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760421_2824.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760420_2660.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760420_7188.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760419_4123.jpg",
};
}
(5)在MainActivity里面引用适配器,设置显示的内容
public class MainActivity extends AppCompatActivity {
private ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.list_view);
ImageAdapter adapter = new ImageAdapter(this, 0, Images.imageUrls);
listView.setAdapter(adapter);
}
}
(6)适配器ImageAdapter
public class ImageAdapter extends ArrayAdapter<String> {
private ListView mListView;
private Bitmap mLoadingBitmap;
/**
* 图片缓存技术的核心类,用于缓存所有下载好的图片,在程序内存达到设定值时会将最少最近使用的图片移除掉。
*/
private LruCache<String, BitmapDrawable> mMemoryCache;
public ImageAdapter(Context context, int resource, String[] objects) {
super(context, resource, objects);
mLoadingBitmap = BitmapFactory.decodeResource(context.getResources(),
R.mipmap.empty_photo);
// 获取应用程序最大可用内存
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) {
if (mListView == null) {
mListView = (ListView) parent;
}
String url = getItem(position);
View view;
if (convertView == null) {
view = LayoutInflater.from(getContext()).inflate(R.layout.images_item, null);
} else {
view = convertView;
}
ImageView image = (ImageView) view.findViewById(R.id.image);
BitmapDrawable drawable = getBitmapFromMemoryCache(url);
if (drawable != null) {
image.setImageDrawable(drawable);
} else if (cancelPotentialWork(url, image)) {
BitmapWorkerTask task = new BitmapWorkerTask(image);
AsyncDrawable asyncDrawable = new AsyncDrawable(getContext()
.getResources(), mLoadingBitmap, task);
image.setImageDrawable(asyncDrawable);
task.execute(url);
}
return view;
}
/**
* 自定义的一个Drawable,让这个Drawable持有BitmapWorkerTask的弱引用。
*/
class AsyncDrawable extends BitmapDrawable {
private WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
public AsyncDrawable(Resources res, Bitmap bitmap,
BitmapWorkerTask bitmapWorkerTask) {
super(res, bitmap);
bitmapWorkerTaskReference = new WeakReference<>(
bitmapWorkerTask);
}
public BitmapWorkerTask getBitmapWorkerTask() {
return bitmapWorkerTaskReference.get();
}
}
/**
* 获取传入的ImageView它所对应的BitmapWorkerTask。
*/
private BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
if (imageView != null) {
Drawable drawable = imageView.getDrawable();
if (drawable instanceof AsyncDrawable) {
AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
return asyncDrawable.getBitmapWorkerTask();
}
}
return null;
}
/**
* 取消掉后台的潜在任务,当认为当前ImageView存在着一个另外图片请求任务时
* ,则把它取消掉并返回true,否则返回false。
*/
public boolean cancelPotentialWork(String url, ImageView imageView) {
BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
if (bitmapWorkerTask != null) {
String imageUrl = bitmapWorkerTask.imageUrl;
if (imageUrl == null || !imageUrl.equals(url)) {
bitmapWorkerTask.cancel(true);
} else {
return false;
}
}
return true;
}
/**
* 将一张图片存储到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> {
String imageUrl;
private WeakReference<ImageView> imageViewReference;
public BitmapWorkerTask(ImageView imageView) {
imageViewReference = new WeakReference<>(imageView);
}
@Override
protected BitmapDrawable doInBackground(String... params) {
imageUrl = params[0];
// 在后台开始下载图片
Bitmap bitmap = downloadBitmap(imageUrl);
BitmapDrawable drawable = new BitmapDrawable(getContext().getResources(), bitmap);
addBitmapToMemoryCache(imageUrl, drawable);
return drawable;
}
@Override
protected void onPostExecute(BitmapDrawable drawable) {
ImageView imageView = getAttachedImageView();
if (imageView != null && drawable != null) {
imageView.setImageDrawable(drawable);
}
}
/**
* 获取当前BitmapWorkerTask所关联的ImageView。
*/
private ImageView getAttachedImageView() {
ImageView imageView = imageViewReference.get();
BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
if (this == bitmapWorkerTask) {
return imageView;
}
return null;
}
/**
* 建立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;
}
}
}
本文摘自 :https://blog.51cto.com/u