首先,ListView中如何下载文字和图片,大家可以看看本人之前的blog
ListView获取网络数据显示。
所以这里关于首次如何下载xml数据,绑定适配器等就不更详细有了,主要是分享如何在ListView中使用ImageLoader这个开源框架如下载图片。
首先介绍一下ImageLoader。用户在快速拖动的时候容易出现卡顿的现象,可能下载不及时完全,然后有时候会可能出现显示错误的item的ImageView等问题,使用开源框架ImageLoader就可以较好的控制这个问题。
首先,使用ImageLoader需要注意的地方,大家可以去看一片blog:http://blog.csdn.net/liweijie_chengxuyuan/article/details/45222167
首先,我们先去配置Application
他的代码如下:需要把他设置在清单文件中,作为application的name属性的值,注意假如该类不再项目包底下,设置需要加上他的完整包路径+类名
import java.io.File; import android.app.Application; import android.content.Context; import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache; import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; import com.nostra13.universalimageloader.core.assist.QueueProcessingType; import com.nostra13.universalimageloader.utils.StorageUtils; public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); initImageLoader(getApplicationContext()); } public static void initImageLoader(Context context) { File cache = StorageUtils.getOwnCacheDirectory(context,"liweijie/cache"); ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context) .threadPriority(Thread.NORM_PRIORITY - 2) //设置ImageLoader的线程的优先级 .threadPoolSize(3) //设置他的线程池的最大数量 推荐1- 5 个,预防OOM,不要设置成太大 .discCache(new UnlimitedDiscCache(cache)) //设置文件缓存到SD卡或者手机的位置 .denyCacheImageMultipleSizesInMemory() // 设置 .discCacheFileNameGenerator(new Md5FileNameGenerator()) // 图片的编码方式MD5编码 .tasksProcessingOrder(QueueProcessingType.LIFO) //默认的 .writeDebugLogs() .build(); ImageLoader.getInstance().init(config); //初始化ImageLoader的配置,必须 } }
ImageLoader采用单例设计模式,ImageLoader imageLoader = ImageLoader.getInstance();得到该对象,每个ImageLoader采用单例设计模式,ImageLoader必须调用init()方法完成初始化。
使用的时候这两点是需要注意的,一个是在Application中intiImageLoader,在清单文件中加入访问网络权限。
然后对于图片的各种设置可以通过DisplayImageOptions 来设置,根据自己的需求进行设置就好。
isplayImageOptions options; options = new DisplayImageOptions.Builder() .showImageOnLoading(R.drawable.ic_launcher) //设置图片在下载期间显示的图片 .showImageForEmptyUri(R.drawable.ic_launcher)//设置图片Uri为空或是错误的时候显示的图片 .showImageOnFail(R.drawable.ic_launcher) //设置图片加载/解码过程中错误时候显示的图片 .cacheInMemory(true)//设置下载的图片是否缓存在内存中 .cacheOnDisc(true)//设置下载的图片是否缓存在SD卡中 .considerExifParams(true) //是否考虑JPEG图像EXIF参数(旋转,翻转) .imageScaleType(ImageScaleType.EXACTLY_STRETCHED)//设置图片以如何的编码方式显示 .bitmapConfig(Bitmap.Config.RGB_565)//设置图片的解码类型// .decodingOptions(android.graphics.BitmapFactory.Options decodingOptions)//设置图片的解码配置 //.delayBeforeLoading(int delayInMillis)//int delayInMillis为你设置的下载前的延迟时间 //设置图片加入缓存前,对bitmap进行设置 //.preProcessor(BitmapProcessor preProcessor) .resetViewBeforeLoading(true)//设置图片在下载前是否重置,复位 .displayer(new RoundedBitmapDisplayer(20))//是否设置为圆角,弧度为多少 .displayer(new FadeInBitmapDisplayer(100))//是否图片加载好后渐入的动画时间 .build();//构建完成
在adapter中下载图片的时候使用到的ImageLoader的方法是displayImage()和loadImage()这两个方法。本篇blog使用displayImage()方法,他比较简单好用。
下载是本demo的详细:
大概项目框架:
MainActivity的代码:他的作用是初始化图片的配置,如上面的DisplayImageOptions ,他是继承于BaseActivity(下面讲),然后他是会开一条线程下载在服务器的xml数据,包含显示的文字和图片的URL,通过使用Handler机制来绑定适配器,一下载数据完全就绑定适配器,适配器运行于UI线程,它里面包含一个ImageLoader对象负责下载对应的image显示出来。
import java.io.IOException; import java.util.ArrayList; import java.util.List; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.Window; import android.widget.ListView; import android.widget.Toast; import com.example.myimageloader.domain.News; import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.display.RoundedBitmapDisplayer; public class MainActivity extends BaseActivity { private DisplayImageOptions options; private ListView listview; private List<News> datas = new ArrayList<News>(); private Handler mHandler = new Handler() { public void handleMessage(android.os.Message msg) { if (msg.what == 1) { System.out.println(((List<News>) msg.obj).size()); listview.setAdapter(new MyListAdapter((List<News>) msg.obj, MainActivity.this, imageLoader, options)); } else if (msg.what == -1) { Toast.makeText(getApplicationContext(), "网络有问题", Toast.LENGTH_SHORT).show(); } }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); listview = (ListView) this.findViewById(R.id.myListView); options = new DisplayImageOptions.Builder().showStubImage(R.drawable.ic_launcher) // 设置图片没有下载完全之前显示的图片 .showImageForEmptyUri(R.drawable.ic_empty) // 设置URL为空的时候或者是错误的时候显示的图片 .showImageOnFail(R.drawable.ic_error) // 设置图片加载或者是解码错误过程中显示的图片 .cacheInMemory(true) // 设置可以缓存在内存中 .cacheOnDisc(true) // 设置可以缓存在SD卡或者手机上 .displayer(new RoundedBitmapDisplayer(20)) // 设置为圆角图片 .build();// 创建配置过得DisplayImageOption对象 new MyThredLoadNews(datas, mHandler).start(); } } final class MyThredLoadNews extends Thread { private List<News> datas; private Handler handler; public MyThredLoadNews (List<News> datas , Handler handler) { this.datas = datas; this.handler = handler; } @Override public void run() { try { datas.addAll(NewsService.getData()); System.out.println(NewsService.getData().size()); Message msg = Message.obtain(); msg.what = 1; msg.obj = datas; handler.sendMessage(msg); } catch (IOException e) { handler.sendEmptyMessage(-1); e.printStackTrace(); } catch (Exception e) { handler.sendEmptyMessage(-1); e.printStackTrace(); } } }
BaseActivity的作用是处理菜单,假如有的手机没有菜单键他点击ActionBar的时候会弹出来,有菜单键则会自动弹出,有两个菜单,一个是清除内存缓存,一个是清除手机本地缓存。并且负责实例化ImageLoader被MainActivity继承,他没有界面,不想要在清单文件声明。
public class BaseActivity extends Activity { protected ImageLoader imageLoader = ImageLoader.getInstance(); @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.item_clear_memory_cache: imageLoader.clearMemoryCache(); return true; case R.id.item_clear_disc_cache: imageLoader.clearDiskCache(); return true; default: return false; } } }
Service类,负责下载和解析xml数据的一个
import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.List; import org.xmlpull.v1.XmlPullParser; import android.util.Xml; import com.example.myimageloader.domain.News; public class NewsService { //下载xml数据 public static List<News> getData() throws Exception, IOException { String path = "http://192.168.1.109:8080/web/mylist1.xml"; HttpURLConnection conn = (HttpURLConnection) new URL(path).openConnection(); conn.setConnectTimeout(5000); conn.setConnectTimeout(5000); conn.setRequestMethod("GET"); if (200 == conn.getResponseCode()) { InputStream stream = conn.getInputStream(); return parserXML(stream); } return null; } <span style="white-space:pre"> </span>//解析xml数据 private static List<News> parserXML(InputStream stream) throws Exception { List<News> datas = new ArrayList<News>(); News news = null; XmlPullParser parser = Xml.newPullParser(); parser.setInput(stream, "UTF-8"); int event = parser.getEventType(); while (event != XmlPullParser.END_DOCUMENT) { switch (event) { case XmlPullParser.START_TAG: if ("image".equals(parser.getName())) { news = new News(); news.name = parser.getAttributeValue(0); break; } if ("path".equals(parser.getName())) { news.path = parser.nextText(); break; } break; case XmlPullParser.END_TAG: if ("image".equals(parser.getName())) { datas.add(news); news = null; break; } break; } event = parser.next(); } return datas; } }
adapter类,他的作用就是联系数据和listview,然后启用ImageLoader下载对应item的图片
import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; import android.content.Context; import android.graphics.Bitmap; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import com.example.myimageloader.domain.News; import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer; import com.nostra13.universalimageloader.core.listener.ImageLoadingListener; import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; public class MyListAdapter extends BaseAdapter { private ImageLoadingListener listener = new FirstDisplatListener(); private List<News> datas = new ArrayList<News>(); private LayoutInflater inflater; private ImageLoader imageLoader; private DisplayImageOptions options; public MyListAdapter (List<News> datas , Context context,ImageLoader imageLoader,DisplayImageOptions options) { this.datas.addAll(datas); inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); this.imageLoader = imageLoader; this.options = options; System.out.println("ok111"); System.out.println(this.datas.size()); } @Override public int getCount() { return datas.size(); } @Override public Object getItem(int position) { return datas.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if (null == convertView) { holder = new ViewHolder(); convertView = inflater.inflate(R.layout.list_item, null); holder.imageView = (ImageView) convertView.findViewById(R.id.image); holder.textView = (TextView) convertView.findViewById(R.id.text); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } System.out.println("okliweijie"); News news = datas.get(position); holder.textView.setText(news.name +"+item " + (position + 1)); imageLoader.displayImage(news.path, holder.imageView, options, listener); return convertView; } private class ViewHolder { public TextView textView; public ImageView imageView; } private static class FirstDisplatListener extends SimpleImageLoadingListener { static final List<String> diaplayImages = Collections.synchronizedList(new LinkedList<String>()); @Override public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { if (loadedImage == null) { ImageView imageView = (ImageView) view; boolean firstDisplay = !diaplayImages.contains(imageUri); if (firstDisplay)// 不存在的时候,这时候是属于第一次显示,使用一个渐变的动画,然后把该uri对应的imageview存放到list中 { FadeInBitmapDisplayer.animate(imageView, 500); diaplayImages.add(imageUri); } } } } }
Application类,配置ImageLoader,在上面第一个。其中News这个类是包含name和path两个属性就不贴代码出来了。结果截图