(android) 如何完成ListView中图片的延迟加载?

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

原问题:How do I do a lazy load of images in 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<String, Drawable> drawableMap; public DrawableManager { drawableMap = new HashMap<String, Drawable>; } public Drawable fetchDrawableString urlString { if drawableMap.containsKeyurlString { return drawableMap.geturlString; } Log.dthis.getClass.getSimpleName, "image url:" + urlString; try { InputStream is = fetchurlString; Drawable drawable = Drawable.createFromStreamis, "src"; if drawable != null { drawableMap.puturlString, drawable; Log.dthis.getClass.getSimpleName, "got a thumbnail drawable: " + drawable.getBounds + ", " + drawable.getIntrinsicHeight + "," + drawable.getIntrinsicWidth + ", " + drawable.getMinimumHeight + "," + drawable.getMinimumWidth; } else { Log.wthis.getClass.getSimpleName, "could not get thumbnail"; } return drawable; } catch MalformedURLException e { Log.ethis.getClass.getSimpleName, "fetchDrawable failed", e; return null; } catch IOException e { Log.ethis.getClass.getSimpleName, "fetchDrawable failed", e; return null; } } public void fetchDrawableOnThreadfinal String urlString, final ImageView imageView { if drawableMap.containsKeyurlString { imageView.setImageDrawabledrawableMap.geturlString; } final Handler handler = new Handler { @Override public void handleMessageMessage message { imageView.setImageDrawableDrawable message.obj; } }; Thread thread = new Thread { @Override public void run { //TODO : set imageView to a "pending" image Drawable drawable = fetchDrawableurlString; Message message = handler.obtainMessage1, drawable; handler.sendMessagemessage; } }; thread.start; } private InputStream fetchString urlString throws MalformedURLException, IOException { DefaultHttpClient httpClient = new DefaultHttpClient; HttpGet request = new HttpGeturlString; HttpResponse response = httpClient.executerequest; return response.getEntity.getContent; }
}

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

public DrawableManager { drawableMap = new HashMap<String, SoftReference<Drawable>>;
} public Drawable fetchDrawableString urlString { SoftReference<Drawable> drawableRef = drawableMap.geturlString; if drawableRef != null { Drawable drawable = drawableRef.get; if drawable != null return drawable; // Reference has expired so remove the key from drawableMap drawableMap.removeurlString; } if Constants.LOGGING Log.dthis.getClass.getSimpleName, "image url:" + urlString; try { InputStream is = fetchurlString; Drawable drawable = Drawable.createFromStreamis, "src"; drawableRef = new SoftReference<Drawable>drawable; drawableMap.puturlString, drawableRef; if Constants.LOGGING Log.dthis.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.ethis.getClass.getSimpleName, "fetchDrawable failed", e; return null; } catch IOException e { if Constants.LOGGING Log.ethis.getClass.getSimpleName, "fetchDrawable failed", e; return null; }
} public void fetchDrawableOnThreadfinal String urlString, final ImageView imageView { SoftReference<Drawable> drawableRef = drawableMap.geturlString; if drawableRef != null { Drawable drawable = drawableRef.get; if drawable != null { imageView.setImageDrawabledrawableRef.get; return; } // Reference has expired so remove the key from drawableMap drawableMap.removeurlString; } final Handler handler = new Handler { @Override public void handleMessageMessage message { imageView.setImageDrawableDrawable message.obj; } }; Thread thread = new Thread { @Override public void run { //TODO : set imageView to a "pending" image Drawable drawable = fetchDrawableurlString; Message message = handler.obtainMessage1, drawable; handler.sendMessagemessage; } }; 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<String, SoftReference<Drawable>> mCache = new HashMap<String, SoftReference<Drawable>>; private final LinkedList <Drawable> mChacheController = new LinkedList <Drawable> ;
private ExecutorService mThreadPool; private final Map<ImageView, String> mImageViews = Collections.synchronizedMapnew WeakHashMap<ImageView, String>; public static int MAX_CACHE_SIZE = 80; public int THREAD_POOL_SIZE = 3; /** * Constructor */
public DrawableBackgroundDownloader { mThreadPool = Executors.newFixedThreadPoolTHREAD_POOL_SIZE; } /** * Clears all instance data and stops running threads */
public void Reset { ExecutorService oldThreadPool = mThreadPool; mThreadPool = Executors.newFixedThreadPoolTHREAD_POOL_SIZE; oldThreadPool.shutdownNow; mChacheController.clear; mCache.clear; mImageViews.clear;
} public void loadDrawablefinal String url, final ImageView imageView,Drawable placeholder { mImageViews.putimageView, url; Drawable drawable = getDrawableFromCacheurl; // check in UI thread, so no concurrency issues if drawable != null { //Log.dnull, "Item loaded from mCache: " + url; imageView.setImageDrawabledrawable; } else { imageView.setImageDrawableplaceholder; queueJoburl, imageView, placeholder; } } private Drawable getDrawableFromCacheString url { if mCache.containsKeyurl { return mCache.geturl.get; } return null; } private synchronized void putDrawableInCacheString url,Drawable drawable { int chacheControllerSize = mChacheController.size; if chacheControllerSize > MAX_CACHE_SIZE mChacheController.subList0, MAX_CACHE_SIZE/2.clear; mChacheController.addLastdrawable; mCache.puturl, new SoftReference<Drawable>drawable; } private void queueJobfinal String url, final ImageView imageView,final Drawable placeholder { /* Create handler in UI thread. */ final Handler handler = new Handler { @Override public void handleMessageMessage msg { String tag = mImageViews.getimageView; if tag != null && tag.equalsurl { if imageView.isShown if msg.obj != null { imageView.setImageDrawableDrawable msg.obj; } else { imageView.setImageDrawableplaceholder; //Log.dnull, "fail " + url; } } } }; mThreadPool.submitnew Runnable { @Override public void run { final Drawable bmp = downloadDrawableurl; // 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.dnull, "Item downloaded: " + url; handler.sendMessagemessage; } } }; } private Drawable downloadDrawableString url { try { InputStream is = getInputStreamurl; Drawable drawable = Drawable.createFromStreamis, url; putDrawableInCacheurl,drawable; return drawable; } catch MalformedURLException e { e.printStackTrace; } catch IOException e { e.printStackTrace; } return null; } private InputStream getInputStreamString urlString throws MalformedURLException, IOException { URL url = new URLurlString; URLConnection connection; connection = url.openConnection; connection.setUseCachestrue; connection.connect; InputStream response = connection.getInputStream; return response;
}
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注