如何完成ListView中图片的延迟加载

我用ListView显示图片和它的标题,这些图片素材都取自于互联网。有什么方法可以让文本显示出来,而图片延迟加载吗?而且,需要让图片按照下载的状态显示出来,其中图片的数量不固定。

 

答:James A Wilson

(最佳答案)

下述代码可以用来控制图片,其中"Log"是一个自定义wrapper,位于Android中最后一个Log class。

 

package com.wilson.android.library; 
/* 
Licensed to the Apache Software Foundation (ASF) under one 
or more contributor license agreements. See the NOTICE file 
distributed with this work for additional information 
regarding copyright ownership. The ASF licenses this file 
to you under the Apache License, Version 2.0 (the 
"License"); you may not use this file except in compliance 
with the License. You may obtain a copy of the License at 
http://www.apache.org/licenses/LICENSE-2.0 
Unless required by applicable law or agreed to in writing, 
software distributed under the License is distributed on an 
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
KIND, either express or implied. See the License for the 
specific language governing permissions and limitations 
under the License. 
*/
import java.io.IOException; 
public class DrawableManager { 
private final Map drawableMap; 
public DrawableManager() { 
drawableMap = new HashMap(); 
} 
public Drawable fetchDrawable(String urlString) { 
if (drawableMap.containsKey(urlString)) { 
return drawableMap.get(urlString); 
} 
Log.d(this.getClass().getSimpleName(), "image url:" + urlString); 
try { 
InputStream is = fetch(urlString); 
Drawable drawable = Drawable.createFromStream(is, "src"); 
if (drawable != null) { 
drawableMap.put(urlString, drawable); 
Log.d(this.getClass().getSimpleName(), "got a thumbnail drawable: " + drawable.getBounds() + ", "
+ drawable.getIntrinsicHeight() + "," + drawable.getIntrinsicWidth() + ", "
+ drawable.getMinimumHeight() + "," + drawable.getMinimumWidth()); 
} else { 
Log.w(this.getClass().getSimpleName(), "could not get thumbnail"); 
} 
return drawable; 
} catch (MalformedURLException e) { 
Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e); 
return null; 
} catch (IOException e) { 
Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e); 
return null; 
} 
} 
public void fetchDrawableOnThread(final String urlString, final ImageView imageView) { 
if (drawableMap.containsKey(urlString)) { 
imageView.setImageDrawable(drawableMap.get(urlString)); 
} 
final Handler handler = new Handler() { 
@Override 
public void handleMessage(Message message) { 
imageView.setImageDrawable((Drawable) message.obj); 
} 
}; 
Thread thread = new Thread() { 
@Override 
public void run() { 
//TODO : set imageView to a "pending" image 
Drawable drawable = fetchDrawable(urlString); 
Message message = handler.obtainMessage(1, drawable); 
handler.sendMessage(message); 
} 
}; 
thread.start(); 
} 
private InputStream fetch(String urlString) throws MalformedURLException, IOException { 
DefaultHttpClient httpClient = new DefaultHttpClient(); 
HttpGet request = new HttpGet(urlString); 
HttpResponse response = httpClient.execute(request); 
return response.getEntity().getContent(); 
} 
}

答:TalkLittle

我选用SoftReference来解决这个问题,但是会在现有的代码基础上做一些改动,因为过去的SoftReference会出现一些图片被当成垃圾处理的情况,但在我的代码中不会出现这种情况,因为我的list size有限,而且图片尺寸也较小。

 

public DrawableManager() { 
drawableMap = new HashMap>(); 
} 
public Drawable fetchDrawable(String urlString) { 
SoftReference drawableRef = drawableMap.get(urlString); 
if (drawableRef != null) { 
Drawable drawable = drawableRef.get(); 
if (drawable != null) 
return drawable; 
// Reference has expired so remove the key from drawableMap 
drawableMap.remove(urlString); 
} 
if (Constants.LOGGING) Log.d(this.getClass().getSimpleName(), "image url:" + urlString); 
try { 
InputStream is = fetch(urlString); 
Drawable drawable = Drawable.createFromStream(is, "src"); 
drawableRef = new SoftReference(drawable); 
drawableMap.put(urlString, drawableRef); 
if (Constants.LOGGING) Log.d(this.getClass().getSimpleName(), "got a thumbnail drawable: " + drawable.getBounds() + ", "
+ drawable.getIntrinsicHeight() + "," + drawable.getIntrinsicWidth() + ", "
+ drawable.getMinimumHeight() + "," + drawable.getMinimumWidth()); 
return drawableRef.get(); 
} catch (MalformedURLException e) { 
if (Constants.LOGGING) Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e); 
return null; 
} catch (IOException e) { 
if (Constants.LOGGING) Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e); 
return null; 
} 
} 
public void fetchDrawableOnThread(final String urlString, final ImageView imageView) { 
SoftReference drawableRef = drawableMap.get(urlString); 
if (drawableRef != null) { 
Drawable drawable = drawableRef.get(); 
if (drawable != null) { 
imageView.setImageDrawable(drawableRef.get()); 
return; 
} 
// Reference has expired so remove the key from drawableMap 
drawableMap.remove(urlString); 
} 
final Handler handler = new Handler() { 
@Override 
public void handleMessage(Message message) { 
imageView.setImageDrawable((Drawable) message.obj); 
} 
}; 
Thread thread = new Thread() { 
@Override 
public void run() { 
//TODO : set imageView to a "pending" image 
Drawable drawable = fetchDrawable(urlString); 
Message message = handler.obtainMessage(1, drawable); 
handler.sendMessage(message); 
} 
}; 
thread.start(); 
}

答:Pinhassi

在看了上述几位的解答方法后,我总结出如下几点:

1.用drawable工作比用bitmap的效率更高

2.虽然SoftReference很好,但是它无法保留一些缓存的图片,所以我添加一个Linked list,以存储下图片列表,防止这些缓存图片被删除。

3.我选择用java.net.URLConnection打开InputStream,这样就可以使用网络缓存(web cache)了。

所以我选用如下代码:

 

import java.util.Map; 
import java.util.HashMap; 
import java.util.LinkedList; 
import java.util.Collections; 
import java.util.WeakHashMap; 
import java.lang.ref.SoftReference; 
import java.util.concurrent.Executors; 
import java.util.concurrent.ExecutorService; 
import android.graphics.drawable.Drawable; 
import android.widget.ImageView; 
import android.os.Handler; 
import android.os.Message; 
import java.io.InputStream; 
import java.net.MalformedURLException; 
import java.io.IOException; 
import java.net.URL; 
import java.net.URLConnection; 
public class DrawableBackgroundDownloader { 
private final Map> mCache = new HashMap>(); 
private final LinkedList  mChacheController = new LinkedList  (); 
private ExecutorService mThreadPool; 
private final Map mImageViews = Collections.synchronizedMap(new WeakHashMap()); 
public static int MAX_CACHE_SIZE = 80; 
public int THREAD_POOL_SIZE = 3; 
/** 
* Constructor 
*/
public DrawableBackgroundDownloader() { 
mThreadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE); 
} 
/** 
* Clears all instance data and stops running threads 
*/
public void Reset() { 
ExecutorService oldThreadPool = mThreadPool; 
mThreadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE); 
oldThreadPool.shutdownNow(); 
mChacheController.clear(); 
mCache.clear(); 
mImageViews.clear(); 
} 
public void loadDrawable(final String url, final ImageView imageView,Drawable placeholder) { 
mImageViews.put(imageView, url); 
Drawable drawable = getDrawableFromCache(url); 
// check in UI thread, so no concurrency issues 
if (drawable != null) { 
//Log.d(null, "Item loaded from mCache: " + url); 
imageView.setImageDrawable(drawable); 
} else { 
imageView.setImageDrawable(placeholder); 
queueJob(url, imageView, placeholder); 
} 
} 
private Drawable getDrawableFromCache(String url) { 
if (mCache.containsKey(url)) { 
return mCache.get(url).get(); 
} 
return null; 
} 
private synchronized void putDrawableInCache(String url,Drawable drawable) { 
int chacheControllerSize = mChacheController.size(); 
if (chacheControllerSize > MAX_CACHE_SIZE) 
mChacheController.subList(0, MAX_CACHE_SIZE/2).clear(); 
mChacheController.addLast(drawable); 
mCache.put(url, new SoftReference(drawable)); 
} 
private void queueJob(final String url, final ImageView imageView,final Drawable placeholder) { 
/* Create handler in UI thread. */ 
final Handler handler = new Handler() { 
@Override 
public void handleMessage(Message msg) { 
String tag = mImageViews.get(imageView); 
if (tag != null && tag.equals(url)) { 
if (imageView.isShown()) 
if (msg.obj != null) { 
imageView.setImageDrawable((Drawable) msg.obj); 
} else { 
imageView.setImageDrawable(placeholder); 
//Log.d(null, "fail " + url); 
} 
} 
} 
}; 
mThreadPool.submit(new Runnable() { 
@Override 
public void run() { 
final Drawable bmp = downloadDrawable(url); 
// if the view is not visible anymore, the image will be ready for next time in cache 
if (imageView.isShown()) 
{ 
Message message = Message.obtain(); 
message.obj = bmp; 
//Log.d(null, "Item downloaded: " + url); 
handler.sendMessage(message); 
} 
} 
}); 
} 
private Drawable downloadDrawable(String url) { 
try { 
InputStream is = getInputStream(url); 
Drawable drawable = Drawable.createFromStream(is, url); 
putDrawableInCache(url,drawable); 
return drawable; 
} catch (MalformedURLException e) { 
e.printStackTrace(); 
} catch (IOException e) { 
e.printStackTrace(); 
} 
return null; 
} 
private InputStream getInputStream(String urlString) throws MalformedURLException, IOException { 
URL url = new URL(urlString); 
URLConnection connection; 
connection = url.openConnection(); 
connection.setUseCaches(true); 
connection.connect(); 
InputStream response = connection.getInputStream(); 
return response; 
} 
}

原文链接:http://stackoverflow.com/questions/541966/how-do-i-do-a-lazy-load-of-images-in-listview

你可能感兴趣的:(Android进阶)