android 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

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

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

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

我选择用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;

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android ,你可以使用 ListView 实现下拉加载功能。下面是实现步骤: 1. 在布局文件添加 ListView 组件,并在其添加一个 ProgressBar 组件作为加载指示器。 ``` <ListView android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="match_parent" /> <ProgressBar android:id="@+id/progressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" /> ``` 2. 在 Activity 或 Fragment 的 onCreate 方法,获取 ListView 组件并设置一个适配器。 ``` ListView listView = (ListView) findViewById(R.id.listView); listView.setAdapter(adapter); ``` 3. 在 onCreate 方法,设置 ListView 的滚动监听器,当滚动到列表底部时触发下拉加载。 ``` listView.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView absListView, int i) {} @Override public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount != 0) { // 到达列表底部,触发下拉加载 loadMoreData(); } } }); ``` 4. 在 loadMoreData 方法,显示 ProgressBar 加载指示器,并开始加载更多数据。 ``` private void loadMoreData() { progressBar.setVisibility(View.VISIBLE); // 加载更多数据 // ... } ``` 5. 加载完成后,隐藏 ProgressBar 加载指示器,并更新 ListView 的适配器。 ``` private void loadMoreData() { progressBar.setVisibility(View.VISIBLE); // 加载更多数据 // ... progressBar.setVisibility(View.GONE); adapter.notifyDataSetChanged(); } ``` 这样就可以实现 ListView 的下拉加载功能了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值