- 浏览: 303218 次
- 性别:
- 来自: 广州
最新评论
-
qipa2015:
hao
Android中自定义SeekBar的背景颜色,进度条颜色,以及滑块的图片 -
chungehenyy:
Android中的JSON详细总结 -
wangys198:
请教下怎么加入一个jar包
说说APK反编译(代码插入)的那点事 -
andy199:
Android的TextView使用Html来处理图片显示、字体样式、超链接等 -
tyjxf:
加载图片是个烦人的事,我也正在困扰中
Android实现ListView异步加载图片
今天在网上找了一整天如何实现ListView显示网络图片的方法
1:显示的图片比较小(1-2张)。这样我觉得不需要使用异步来加载,直接使用位图显示就OK
2:显示的图片比较多,可以使用异步加载。但存在BUG:单显示的条目很多。ListView需要往下拉的时候。图片不能显示,但是使用1的方法却能全部显示出来
参考资料:http://hulefei29.iteye.com/blog/616262
例子:
1、定义主界面,在界面里面添加一个ListView控件
main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="fill_parent"> <TextView android:id="@+id/indexTitle" android:layout_width="fill_parent" android:gravity="center" android:layout_height="wrap_content" android:text="使用ListView显示图片"/> <ListView android:id="@+id/searchList" android:layout_width="fill_parent" android:layout_height="wrap_content" android:choiceMode="singleChoice" /> </LinearLayout>
2、定义Item页面
search_list.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content"> <ImageView android:id="@+id/stationImg" android:layout_width="wrap_content" android:layout_height="wrap_content" android:minWidth="80px" android:maxWidth="80px" android:minHeight="45px" android:maxHeight="45px" android:scaleType="fitXY" android:src="@drawable/icon" android:layout_margin="5px"/> <LinearLayout android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:id="@+id/stationTitle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#FFFFFFFF" android:textSize="22px" /> <TextView android:id="@+id/stationInfo" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#FFFFFFFF" android:textSize="13px" /> </LinearLayout> </LinearLayout>
三、定义MainActivity
MainActivity.java
package lee.listviewimage; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import lee.listviewimage.R; import android.app.Activity; import android.os.Bundle; import android.widget.ListView; public class MainActivity extends Activity { // private List<Map<String, Object>> generateData(List<XXXX> xxxxs) { // List<Map<String, Object>> resList = new ArrayList<Map<String, Object>>(); // for (Iterator<XXXX> iterator = xxxxs.iterator(); iterator // .hasNext();) { // XXXX xxxx= (XXXX) iterator.next(); // Map<String, Object> resMap = new HashMap<String, Object>(); // resMap.put("title", xxxx.getTitle()); // resMap.put("info", xxxx.getInfo()); // resMap.put("img", xxxx.getImageUrl()); // resList.add(resMap); // } // return resList; // } ListView view; List<Map<String, Object>> resList; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); view = (ListView) findViewById(R.id.searchList); resList = new ArrayList<Map<String, Object>>(); Map<String, Object> resMap = new HashMap<String, Object>(); resMap.put("title", "title111"); resMap.put("info", "111111"); resMap.put("img", "http://tb.himg.baidu.com/sys/portrait/item/d71e5a30323837797979d300"); resList.add(resMap); resMap = new HashMap<String, Object>(); resMap.put("title", "title222"); resMap.put("info", "222222"); resMap.put("img", "http://img.baidu.com/img/post-jg.gif"); resList.add(resMap); SearchAdapter adapter = new SearchAdapter( this,resList, R.layout.search_list, new String[] {"title", "info", "img" }, new int[] {R.id.stationTitle, R.id.stationInfo,R.id.stationImg }); view.setAdapter(adapter); } }
四、定义通过图片url返回图片Bitmap的工具类"(如果不需要异步,直接调用这个方法)
WebImageBuilder.java
package lee.listviewimage; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import android.graphics.Bitmap; import android.graphics.BitmapFactory; public class WebImageBuilder { /** * 通过图片url返回图片Bitmap * @param url * @return */ public static Bitmap returnBitMap(String path) { URL url = null; Bitmap bitmap = null; try { url = new URL(path); } catch (MalformedURLException e) { e.printStackTrace(); } try { HttpURLConnection conn = (HttpURLConnection) url.openConnection();//利用HttpURLConnection对象,我们可以从网络中获取网页数据. conn.setDoInput(true); conn.connect(); InputStream is = conn.getInputStream(); //得到网络返回的输入流 bitmap = BitmapFactory.decodeStream(is); is.close(); } catch (IOException e) { e.printStackTrace(); } return bitmap; } }
五、定义异步加载图片的工具类
AsyncImageLoader.java
package lee.listviewimage; import java.lang.ref.SoftReference; import java.net.URL; import java.util.HashMap; import java.util.Map; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Message; public class AsyncImageLoader { private Map<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>(); public Drawable loadDrawable(final String imageUrl,final ImageCallback callback) { if (imageCache.containsKey(imageUrl)) { SoftReference<Drawable> softReference = imageCache.get(imageUrl); if (softReference.get() != null) { return softReference.get(); } } final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { callback.imageLoaded((Drawable) msg.obj, imageUrl); } }; //load data new Thread() { public void run() { Drawable drawable = loadImageFromUrl(imageUrl); imageCache.put(imageUrl, new SoftReference<Drawable>(drawable)); handler.sendMessage(handler.obtainMessage(0, drawable)); }; }.start(); return null; } protected Drawable loadImageFromUrl(String imageUrl) { try { return Drawable.createFromStream(new URL(imageUrl).openStream(), "src"); } catch (Exception e) { throw new RuntimeException(e); } } //call back interface public interface ImageCallback { public void imageLoaded(Drawable imageDrawable, String imageUrl); } }
六、定义异步加载图片的方法
PS:原文章说只有 public SearchAdapter构造方法和 public void setViewImage(final ImageView v, String url)有用,其他都是源代码。理论上可以去掉不写,但去掉后确不能正常显示图片,有全部都是同一张图片,或者只显示1条数据,但去掉的方法却可以不在异步的显示图片中测试成功。(看第七点)
SearchAdapter.java
package lee.listviewimage; import java.util.HashMap; import java.util.List; import java.util.Map; import android.content.Context; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Checkable; import android.widget.ImageView; import android.widget.SimpleAdapter; import android.widget.TextView; public class SearchAdapter extends SimpleAdapter { private AsyncImageLoader imageLoader = new AsyncImageLoader(); private Map<Integer, View> viewMap = new HashMap<Integer, View>(); private ViewBinder mViewBinder; private List<? extends Map<String, ?>> mData; //List列表存放的数据 private int mResource; //绑定的页面 ,例如:R.layout.search_item, private LayoutInflater mInflater; private String[] mFrom; //绑定控件对应的数组里面的值名称 private int[] mTo; //绑定控件的ID //构造器 public SearchAdapter(Context context, List<? extends Map<String, ?>> data,int resource, String[] from, int[] to) { super(context, data, resource, from, to); mData = data; mResource = resource; mFrom = from; mTo = to; // 布局泵(LayoutInflater)根据XML布局文件来绘制视图(View)对象。这个类无法直接创建实例,要通过context对象的getLayoutInflater()或getSystemService(String)方法来获得实例,这样获得的布局泵实例符合设备的环境配置。 mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } /* SimpleAdapter基类显示每个Item都是通过这个方法生成的 在getView(int position, View convertView, ViewGroup parent)中又调用了SimpleAdapter的私有方法createViewFromResource 来组装View,在createViewFromResource中对SimpleAdapter的参数String[] from 和int[] to进行了组装 */ public View getView(int position, View convertView, ViewGroup parent) { return createViewFromResource(position, convertView, parent, mResource); //调用下面方法 } //在createViewFromResource方法中又有一个bindView(position, v)方法对item中的各个View进行了组装,bindView(position, v) private View createViewFromResource(int position, View convertView, ViewGroup parent, int resource) { View rowView = this.viewMap.get(position); if (rowView == null) { rowView = mInflater.inflate(resource, null); final int[] to = mTo; final int count = to.length; final View[] holder = new View[count]; for (int i = 0; i < count; i++) { holder[i] = rowView.findViewById(to[i]); } rowView.setTag(holder); bindView(position, rowView); //调用下面方法对Item中的 viewMap.put(position, rowView); } return rowView; } //对ViewImage进行组装的代码了“else if (v instanceof ImageView)” @SuppressWarnings("unchecked") private void bindView(int position, View view) { final Map dataSet = mData.get(position); if (dataSet == null) { return; } final ViewBinder binder = mViewBinder; final View[] holder = (View[]) view.getTag(); final String[] from = mFrom; final int[] to = mTo; final int count = to.length; for (int i = 0; i < count; i++) { final View v = holder[i]; if (v != null) { final Object data = dataSet.get(from[i]); String urlText = null; if (data == null) { urlText = ""; } else { urlText = data.toString(); } boolean bound = false; if (binder != null) { bound = binder.setViewValue(v, data, urlText); } if (!bound) { if (v instanceof Checkable) { if (data instanceof Boolean) { ((Checkable) v).setChecked((Boolean) data); } else { throw new IllegalStateException(v.getClass() .getName() + " should be bound to a Boolean, not a " + data.getClass()); } } else if (v instanceof TextView) { setViewText((TextView) v, urlText); } else if (v instanceof ImageView) { if (data instanceof Integer) { setViewImage((ImageView) v, (Integer) data); } else { setViewImage((ImageView) v, urlText); } } else { throw new IllegalStateException( v.getClass().getName() + " is not a " + " view that can be bounds by this SimpleAdapter"); } } } } } public void setViewImage(ImageView v, int value) { v.setImageResource(value); } public void setViewImage(final ImageView v, String url) { //如果只是单纯的把图片显示,而不进行缓存。直接用下面的方法拿到URL的Bitmap就行显示就OK // Bitmap bitmap = WebImageBuilder.returnBitMap(url); // ((ImageView) v).setImageBitmap(bitmap); imageLoader.loadDrawable(url, new AsyncImageLoader.ImageCallback() { public void imageLoaded(Drawable imageDrawable, String imageUrl) { if(imageDrawable!=null && imageDrawable.getIntrinsicWidth()>0 ) { v.setImageDrawable(imageDrawable); } } }); } }
七、如果不需要异步加载,可以修改上面的SearchAdapter方法
(1):可以在上面的基础上修改public void setViewImage(final ImageView v, String url)方法
public void setViewImage(final ImageView v, String url) { Bitmap bitmap = WebImageBuilder.returnBitMap(url); ((ImageView) v).setImageBitmap(bitmap); }
(2)可以只剩下public SearchAdapter构造方法和 public void setViewImage(final ImageView v, String url)2个方法,其他方法都去掉
package lee.listviewimage; import java.util.List; import java.util.Map; import android.content.Context; import android.graphics.Bitmap; import android.widget.ImageView; import android.widget.SimpleAdapter; public class SearchAdapter extends SimpleAdapter { //构造器 public SearchAdapter(Context context, List<? extends Map<String, ?>> data,int resource, String[] from, int[] to) { super(context, data, resource, from, to); } public void setViewImage(final ImageView v, String url) { Bitmap bitmap = WebImageBuilder.returnBitMap(url); ((ImageView) v).setImageBitmap(bitmap); } }
如果只是打开单个图片可以使用这个方法
PS:异步方法应该也可以精简到上面那样只剩下2个方法,但测试不成功。,有待修改
问题1:
今天测试的时候又发现了问题:单图片的地址错误或者无法连接时,使用异步的方法虽然能正常显示其他图片,但单连接错误的图片超时后。系统会自动跳出提示错误信息。原来源文件没有处理这种情况,所以需要对异步的AsyncImageLoader.java文件的loadImageFromUrl方法进行修改
//定义方法链接URL获取输入流,然后转换成Drawable protected Drawable loadImageFromUrl(String imageUrl) { try { return Drawable.createFromStream(new URL(imageUrl).openStream(),"src");//当URL不正确或者链接不上。new URL(imageUrl).openStream()会抛错。所以需要在抛错的时候返回NULL。 } catch (Exception e) { // throw new RuntimeException(e); return Drawable.createFromStream(null,"src"); } }:
问题2:
单显示的条目很多。需要Listview往下拉,这样当翻页的图片如果是第一页相同的图片。会出现不能显示的问题,这样就导致了没有缓冲的同能。
原因:
主要是因为
这段代码没有起作用。因为他只是直接返回softReference.get();结果。并没有对他进行显示 if (imageCache.containsKey(imageUrl)) {
SoftReference<Drawable> softReference = imageCache.get(imageUrl);
if (softReference.get() != null) {
return softReference.get();
}
}
解决:
把上面的代码放到线程里面去。同时优化了一下。加了线程池管理线程启动的个数
try { threadPool.execute(new Runnable() { @Override public void run() { if (imageCache.containsKey(imageUrl)) { //检查缓冲imageCache是否存在对应的KEY SoftReference<Drawable> softReference = imageCache.get(imageUrl); //存在就获取对应的值 Log.i("abc", "1:"+softReference.get().toString()); if (softReference.get() != null) { Log.i("abc", "2:"+softReference.get().toString()); Message message = handler.obtainMessage(0, softReference.get()); handler.sendMessage(message); } }else{ Drawable drawable = loadImageFromUrl(imageUrl); //使用下面的方法获取Drawable imageCache.put(imageUrl, new SoftReference<Drawable>(drawable)); //把图片放到HasMap中 Log.i("abc", "0:"+drawable); Message message = handler.obtainMessage(0, drawable); handler.sendMessage(message); } } }); } catch (Exception e) { e.printStackTrace(); }
- ListView异步显示图片.rar (61.6 KB)
- 下载次数: 815
评论
发表评论
-
Android 学习资料大集合
2012-02-22 11:23 2546<script type="t ... -
总结了近百个Android优秀开源项目,覆盖Android开发的每个
2012-02-21 11:21 1955Android开发又将带来新一轮热潮,很多开发者都投入到这 ... -
说说APK反编译(代码插入)的那点事
2012-02-21 09:54 9061很多人热衷于逆向工程,其过程中既可以学习作者的思路,又可以锻炼 ... -
(转)一种新的MAT使用方法分析内存溢出问题
2012-02-21 09:42 1985相信很多人都用过MAT来分析内存溢出,而且网上有很多的使用方法 ... -
(转)Android* 应用性能调试
2012-02-08 09:33 1505概述 创造愉快用户体验的关键是开发响应快捷的应用。借助And ... -
Android SDK 中Android.net.wi
2012-02-06 15:20 1846这里列了很多,但是大致可以分为四个主要的类ScanResult ... -
android 从assets和res中读取文件(转)
2012-02-03 15:02 25321. 相关文件夹介绍 ... -
textview 超链接去掉下划线和设置超链接颜色
2011-12-06 17:15 3782/** * 点击超链接时打开其他博主资料页面 * ... -
按钮Listview等点击效果
2011-11-12 22:58 4011想设置listview中每行在点击、选中等不同状态下有不同的背 ... -
android 获取视频和图片的缩略图
2011-11-12 01:53 118111 在显示视频图片列表时,发送彩信时,制作幻灯片时都需要显示视 ... -
调用android系统图标
2011-10-31 16:54 2842Android系统中自带了很多图标,我们的程序可以方便使用。 ... -
The content of the adapter has changed but ListView did not receive a notificati
2011-10-27 15:43 1163在Android开发过程中,使用了大量的ListView,发现 ... -
android的上下文菜单---context menu
2011-09-23 09:53 1254android的菜单有三种: ... -
选择系统图片方法时返回图片真实路径
2011-09-21 10:36 1617protected void onActivityResul ... -
android一些技巧
2011-09-01 18:08 1501EditText ed = ... -
android TextView中超链接的事件捕捉(textview上LINK的点击事件)
2011-08-19 18:43 2523package com.cm; import java. ... -
Android的TextView使用Html来处理图片显示、字体样式、超链接等
2011-08-19 18:38 4550转载:http://my.oschina.net/java ... -
Android 设置EditText显示或隐藏密码
2011-08-17 16:37 2228设置EditText显示或隐藏密码. 在CheckBox的o ... -
android调用系统资源裁剪图片
2011-08-08 12:52 28381 import java.io.File; 2 import ... -
Android 复制 粘贴
2011-07-25 10:18 2521Android 复制 粘贴 ClipboardManager ...
相关推荐
本文实例讲述了Android实现ListView异步加载图片的方法。分享给大家供大家参考。具体如下: ListView异步加载图片是非常实用的方法,凡是是要通过网络获取图片资源一般使用这种方法比较好,用户体验好,不用让用户...
Android Listview异步加载图片,图片错位解决方案
Android 异步加载图片,对ListView的异步加载图片的功能演示,主要根据url读取图片返回流的方法。为了方便演示,将请求图片的链接先固定,每读取好一个图片就更新,界面比较简单,当然你可以做成比较好的,像很多好...
android listview异步加载图片实例 用到了线程池 下载的图片会保存到本地 并在数据库中保留记录 再次加载时会直接从本地读取
android listView图片异步加载(拖动时不加载,双缓存)
android中ListView异步加载图片时的图片错位问题解决方案
本文实例讲述了Android实现Listview异步加载网络图片并动态更新的方法。分享给大家供大家参考,具体如下: 应用实例:解析后台返回的数据,把每条都显示在ListView中,包括活动图片、店名、活动详情、地址、电话和...
android listview 异步加载网络图片
android中ListView异步加载图片时的图片错位问题解决方案
NULL 博文链接:https://zjingye.iteye.com/blog/1936268
①ListView异步加载图片的方式 ②给ImageView设置Tag,解决图片覆盖问题 ③采用LruCache缓存已经加载过的图片 ④当ListView滚动时不加载图片,滚动停止时才加载图片,从而达到ListView滑动很流畅的效果 ⑤当...
Android ListView 异步加载图片,一点也不卡,使用AsyncTask和WeakReference,注释详尽
Android ListView异步加载图片,优化滚动效果,不卡顿、流畅显示。主要给新人了解ListView和AsyncTask、Json等使用。
AystnPicture_Android ListView异步加载图片.rar
Android中ListView全面完美的网络图片的异步加载,两种加载方式,利用了LruCache缓存,动态加载,只加载可见部分的图片.