上一篇文章说的是ListView展示本地的图片以及文本,这一篇说一下如何从网络获取图片以及文本来显示。事实上,一般是先获取Josn或sml数据,然后解释显示。我们先从网上获取xml,然后对其进行解析,最后显示在ListView上。具体步骤:
客户端发出请求,获取xml
客户端异步解析xml
ListView将解析完的数据显示
(1)xml布局文件
mainxml,就是一个ListView。
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
android:id="@+id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:divider="#b5b5b5"
android:dividerHeight="1dp"
android:listSelector="@drawable/list_selector"/>
ListView的每一行的布局,list_raw.xml,看一下结构图:
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/list_selector"
android:orientation="horizontal"
android:padding="5dip">
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="3dip"
android:layout_alignParentLeft="true"
android:background="@drawable/image_bg"
android:layout_marginRight="5dip">
android:id="@+id/list_image"
android:layout_width="50dip"
android:layout_height="50dip"
android:src="@drawable/rihanna"/>
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/thumbnail"
android:layout_toRightOf="@+id/thumbnail"
android:text="RihannaLovethewaylie"
android:textColor="#040404"
android:typeface="sans"
android:textSize="15dip"
android:textStyle="bold"/>
android:id="@+id/artist"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/title"
android:textColor="#343434"
android:textSize="10dip"
android:layout_marginTop="1dip"
android:layout_toRightOf="@+id/thumbnail"
android:text="Justgonastandthereand..."/>
android:id="@+id/duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignTop="@id/title"
android:gravity="right"
android:text="5:45"
android:layout_marginRight="5dip"
android:textSize="10dip"
android:textColor="#10bcc9"
android:textStyle="bold"/>
android:layout_height="wrap_content"
android:src="@drawable/arrow"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"/>
另外我们打算使用几个特效,一个是当点击列表项目的时候,项目背景色改变,其实就是一个selector;另一个就是用shape美化视觉效果,具体看xml代码:
1.list_selector.xml
android:state_selected="false"
android:state_pressed="false"
android:drawable="@drawable/gradient_bg"/>
android:drawable="@drawable/gradient_bg_hover"/>
android:state_pressed="false"
android:drawable="@drawable/gradient_bg_hover"/>
2.gradient_bg.xml,是默认背景梯度风格
android:shape="rectangle">
android:startColor="#f1f1f2"
android:centerColor="#e7e7e8"
android:endColor="#cfcfcf"
android:angle="270"/>
3.gradient_bg_hover.xml梯度风格在悬停状态
android:shape="rectangle">
android:startColor="#18d7e5"
android:centerColor="#16cedb"
android:endColor="#09adb9"
android:angle="270"/>
4.image_bg.xml在图片周围的白色边条
android:shape="rectangle">
以上效果基本上都用到了shape,对此不了解的可以去查看相关资料。上面就是全部的xml布局文件,下面将开始写代码。
(2)主要代码
代码部分主要涉及到一下几个功能,重写ListView的适配器(BaseAdapter),从网络获取图片,图片缓存的处理,xml的解析。
①重写ListView的适配器,这部分可以参考上一篇文章,LazyAdapter.Java
importjava.util.ArrayList;
importjava.util.HashMap;
importandroid.app.Activity;
importandroid.content.Context;
importandroid.view.LayoutInflater;
importandroid.view.View;
importandroid.view.ViewGroup;
importandroid.widget.BaseAdapter;
importandroid.widget.ImageView;
importandroid.widget.TextView;
publicclassLazyAdapterextendsBaseAdapter{
privateActivityactivity;
privateArrayList>data;
privatestaticLayoutInflaterinflater=null;
publicImageLoaderimageLoader;//用来下载图片的类,后面有介绍
publicLazyAdapter(Activitya,ArrayList>d){
activity=a;
data=d;
inflater=(LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
imageLoader=newImageLoader(activity.getApplicationContext());
}
publicintgetCount(){
returndata.size();
}
publicObjectgetItem(intposition){
returnposition;
}
publiclonggetItemId(intposition){
returnposition;
}
publicViewgetView(intposition,ViewconvertView,ViewGroupparent){
Viewvi=convertView;
if(convertView==null)
vi=inflater.inflate(R.layout.list_row,null);
TextViewtitle=(TextView)vi.findViewById(R.id.title);//标题
TextViewartist=(TextView)vi.findViewById(R.id.artist);//歌手名
TextViewduration=(TextView)vi.findViewById(R.id.duration);//时长
ImageViewthumb_image=(ImageView)vi.findViewById(R.id.list_image);//缩略图
HashMapsong=newHashMap();
song=data.get(position);
//设置ListView的相关值
title.setText(song.get(CustomizedListView.KEY_TITLE));
artist.setText(song.get(CustomizedListView.KEY_ARTIST));
duration.setText(song.get(CustomizedListView.KEY_DURATION));
imageLoader.DisplayImage(song.get(CustomizedListView.KEY_THUMB_URL),thumb_image);
returnvi;
}
}
②网络获取图片的类,ImageLoader.java:
importjava.io.File;
importjava.io.FileInputStream;
importjava.io.FileNotFoundException;
importjava.io.FileOutputStream;
importjava.io.InputStream;
importjava.io.OutputStream;
.HttpURLConnection;
.URL;
importjava.util.Collections;
importjava.util.Map;
importjava.util.WeakHashMap;
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
importandroid.app.Activity;
importandroid.content.Context;
importandroid.graphics.Bitmap;
importandroid.graphics.BitmapFactory;
importandroid.widget.ImageView;
publicclassImageLoader{
MemoryCachememoryCache=newMemoryCache();
FileCachefileCache;
privateMapimageViews=Collections.synchronizedMap(newWeakHashMap());
ExecutorServiceexecutorService;
publicImageLoader(Contextcontext){
fileCache=newFileCache(context);
executorService=Executors.newFixedThreadPool(5);
}
finalintstub_id=R.drawable.no_image;
publicvoidDisplayImage(Stringurl,ImageViewimageView)
{
imageViews.put(imageView,url);
Bitmapbitmap=memoryCache.get(url);
if(bitmap!=null)
imageView.setImageBitmap(bitmap);
else
{
queuePhoto(url,imageView);
imageView.setImageResource(stub_id);
}
}
privatevoidqueuePhoto(Stringurl,ImageViewimageView)
{
PhotoToLoadp=newPhotoToLoad(url,imageView);
executorService.submit(newPhotosLoader(p));
}
privateBitmapgetBitmap(Stringurl)
{
Filef=fileCache.getFile(url);
//从sd卡
Bitmapb=decodeFile(f);
if(b!=null)
returnb;
//从网络
try{
Bitmapbitmap=null;
URLimageUrl=newURL(url);
HttpURLConnectionconn=(HttpURLConnection)imageUrl.openConnection();
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
conn.setInstanceFollowRedirects(true);
InputStreamis=conn.getInputStream();
OutputStreamos=newFileOutputStream(f);
Utils.CopyStream(is,os);
os.close();
bitmap=decodeFile(f);
returnbitmap;
}catch(Exceptionex){
ex.printStackTrace();
returnnull;
}
}
//解码图像用来减少内存消耗
privateBitmapdecodeFile(Filef){
try{
//解码图像大小
BitmapFactory.Optionso=newBitmapFactory.Options();
o.inJustDecodeBounds=true;
BitmapFactory.decodeStream(newFileInputStream(f),null,o);
//找到正确的刻度值,它应该是2的幂。
finalintREQUIRED_SIZE=70;
intwidth_tmp=o.outWidth,height_tmp=o.outHeight;
intscale=1;
while(true){
if(width_tmp/2
break;
width_tmp/=2;
height_tmp/=2;
scale*=2;
}
BitmapFactory.Optionso2=newBitmapFactory.Options();
o2.inSampleSize=scale;
returnBitmapFactory.decodeStream(newFileInputStream(f),null,o2);
}catch(FileNotFoundExceptione){}
returnnull;
}
/任务队列
privateclassPhotoToLoad
{
publicStringurl;
publicImageViewimageView;
publicPhotoToLoad(Stringu,ImageViewi){
url=u;
imageView=i;
}
}
classPhotosLoaderimplementsRunnable{
PhotoToLoadphotoToLoad;
PhotosLoader(PhotoToLoadphotoToLoad){
this.photoToLoad=photoToLoad;
}
@Override
publicvoidrun(){
if(imageViewReused(photoToLoad))
return;
Bitmapbmp=getBitmap(photoToLoad.url);
memoryCache.put(photoToLoad.url,bmp);
if(imageViewReused(photoToLoad))
return;
BitmapDisplayerbd=newBitmapDisplayer(bmp,photoToLoad);
Activitya=(Activity)photoToLoad.imageView.getContext();
a.runOnUiThread(bd);
}
}
booleanimageViewReused(PhotoToLoadphotoToLoad){
Stringtag=imageViews.get(photoToLoad.imageView);
if(tag==null||!tag.equals(photoToLoad.url))
returntrue;
returnfalse;
}
//用于显示位图在UI线程
classBitmapDisplayerimplementsRunnable
{
Bitmapbitmap;
PhotoToLoadphotoToLoad;
publicBitmapDisplayer(Bitmapb,PhotoToLoadp){bitmap=b;photoToLoad=p;}
publicvoidrun()
{
if(imageViewReused(photoToLoad))
return;
if(bitmap!=null)
photoToLoad.imageView.setImageBitmap(bitmap);
else
photoToLoad.imageView.setImageResource(stub_id);
}
}
publicvoidclearCache(){
memoryCache.clear();
fileCache.clear();
}
} ③xml解析,xml的解析有很多方法,这里采用进行dom方式的xml解析。
importjava.io.IOException;
importjava.io.StringReader;
importjava.io.UnsupportedEncodingException;
importjavax.xml.parsers.DocumentBuilder;
importjavax.xml.parsers.DocumentBuilderFactory;
importjavax.xml.parsers.ParserConfigurationException;
importorg.apache.http.HttpEntity;
importorg.apache.http.HttpResponse;
importorg.apache.http.client.ClientProtocolException;
importorg.apache.http.client.methods.HttpPost;
importorg.apache.http.impl.client.DefaultHttpClient;
importorg.apache.http.util.EntityUtils;
importorg.w3c.dom.Document;
importorg.w3c.dom.Element;
importorg.w3c.dom.Node;
importorg.w3c.dom.NodeList;
importorg.xml.sax.InputSource;
importorg.xml.sax.SAXException;
importandroid.util.Log;
publicclassXMLParser{
//构造方法
publicXMLParser(){
}
/**
*从URL获取XML使HTTP请求
*@paramurlstring
**/
publicStringgetXmlFromUrl(Stringurl){
Stringxml=null;
try{
//defaultHttpClient
DefaultHttpClienthttpClient=newDefaultHttpClient();
HttpPosthttpPost=newHttpPost(url);
HttpResponsehttpResponse=httpClient.execute(httpPost);
HttpEntityhttpEntity=httpResponse.getEntity();
xml=EntityUtils.toString(httpEntity);
}catch(UnsupportedEncodingExceptione){
e.printStackTrace();
}catch(ClientProtocolExceptione){
e.printStackTrace();
}catch(IOExceptione){
e.printStackTrace();
}
returnxml;
}
/**
*获取XMLDOM元素
*@paramXMLstring
**/
publicDocumentgetDomElement(Stringxml){
Documentdoc=null;
DocumentBuilderFactorydbf=DocumentBuilderFactory.newInstance();
try{
DocumentBuilderdb=dbf.newDocumentBuilder();
InputSourceis=newInputSource();
is.setCharacterStream(newStringReader(xml));
doc=db.parse(is);
}catch(ParserConfigurationExceptione){
Log.e("Error:",e.getMessage());
returnnull;
}catch(SAXExceptione){
Log.e("Error:",e.getMessage());
returnnull;
}catch(IOExceptione){
Log.e("Error:",e.getMessage());
returnnull;
}
returndoc;
}
/**获取节点值
*@paramelemelement
*/
publicfinalStringgetElementValue(Nodeelem){
Nodechild;
if(elem!=null){
if(elem.hasChildNodes()){
for(child=elem.getFirstChild();child!=null;child=child.getNextSibling()){
if(child.getNodeType()==Node.TEXT_NODE){
returnchild.getNodeValue();
}
}
}
}
return"";
}
/**
*获取节点值
*@paramElementnode
*@paramkeystring
**/
publicStringgetValue(Elementitem,Stringstr){
NodeListn=item.getElementsByTagName(str);
returnthis.getElementValue(n.item(0));
}
} ④程序缓存的处理,主要是内存缓存+文件缓存。内存缓存中网上很多是采用SoftReference来防止堆溢出:
MemoryCache.java:
importjava.lang.ref.SoftReference;
importjava.util.Collections;
importjava.util.HashMap;
importjava.util.Map;
importandroid.graphics.Bitmap;
publicclassMemoryCache{
privateMap>cache=Collections.synchronizedMap(newHashMap>());//软引用
publicBitmapget(Stringid){
if(!cache.containsKey(id))
returnnull;
SoftReferenceref=cache.get(id);
returnref.get();
}
publicvoidput(Stringid,Bitmapbitmap){
cache.put(id,newSoftReference(bitmap));
}
publicvoidclear(){
cache.clear();
}
} FileCache.java
importjava.io.File;
importandroid.content.Context;
publicclassFileCache{
privateFilecacheDir;
publicFileCache(Contextcontext){
//找一个用来缓存图片的路径
if(android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
cacheDir=newFile(android.os.Environment.getExternalStorageDirectory(),"LazyList");
else
cacheDir=context.getCacheDir();
if(!cacheDir.exists())
cacheDir.mkdirs();
}
publicFilegetFile(Stringurl){
Stringfilename=String.valueOf(url.hashCode());
Filef=newFile(cacheDir,filename);
returnf;
}
publicvoidclear(){
File[]files=cacheDir.listFiles();
if(files==null)
return;
for(Filef:files)
f.delete();
}
}⑤还有一个读取流的工具类,Utils.java:
importjava.io.InputStream;
importjava.io.OutputStream;
publicclassUtils{
publicstaticvoidCopyStream(InputStreamis,OutputStreamos)
{
finalintbuffer_size=1024;
try
{
byte[]bytes=newbyte[buffer_size];
for(;;)
{
intcount=is.read(bytes,0,buffer_size);
if(count==-1)
break;
os.write(bytes,0,count);
is.close();
os.close();
}
}
catch(Exceptionex){}
}
}
还可以像下面这样表达,方法是一样的,就是表达形式上不同:
publicstaticbyte[]readStream(InputStreaminStream)throwsException{
ByteArrayOutputStreamoutSteam=newByteArrayOutputStream();
byte[]buffer=newbyte[1024];
intlen=-1;
while((len=inStream.read(buffer))!=-1){
outSteam.write(buffer,0,len);
}
outSteam.close();
inStream.close();
returnoutSteam.toByteArray();
}
} 最后就是主Activity的代码了,
packagecom.example.androidhive;
importjava.util.ArrayList;
importjava.util.HashMap;
importorg.w3c.dom.Document;
importorg.w3c.dom.Element;
importorg.w3c.dom.NodeList;
importandroid.app.Activity;
importandroid.os.Bundle;
importandroid.view.View;
importandroid.widget.AdapterView;
importandroid.widget.AdapterView.OnItemClickListener;
importandroid.widget.ListView;
publicclassCustomizedListViewextendsActivity{
//所有的静态变量
staticfinalStringURL="http://api.androidhive.info/music/music.xml";//xml目的地址,打开地址看一下
//XML节点
staticfinalStringKEY_SONG="song";//parentnode
staticfinalStringKEY_ID="id";
staticfinalStringKEY_TITLE="title";
staticfinalStringKEY_ARTIST="artist";
staticfinalStringKEY_DURATION="duration";
staticfinalStringKEY_THUMB_URL="thumb_url";
ListViewlist;
LazyAdapteradapter;
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ArrayList>songsList=newArrayList>();
XMLParserparser=newXMLParser();
Stringxml=parser.getXmlFromUrl(URL);//从网络获取xml
Documentdoc=parser.getDomElement(xml);//获取DOM节点
NodeListnl=doc.getElementsByTagName(KEY_SONG);
//循环遍历所有的歌节点
for(inti=0;i
//新建一个HashMap
HashMapmap=newHashMap();
Elemente=(Element)nl.item(i);
//每个子节点添加到HashMap关键=>值
map.put(KEY_ID,parser.getValue(e,KEY_ID));
map.put(KEY_TITLE,parser.getValue(e,KEY_TITLE));
map.put(KEY_ARTIST,parser.getValue(e,KEY_ARTIST));
map.put(KEY_DURATION,parser.getValue(e,KEY_DURATION));
map.put(KEY_THUMB_URL,parser.getValue(e,KEY_THUMB_URL));
//HashList添加到数组列表
songsList.add(map);
}
list=(ListView)findViewById(R.id.list);
adapter=newLazyAdapter(this,songsList);
list.setAdapter(adapter);
//为单一列表行添加单击事件
list.setOnItemClickListener(newOnItemClickListener(){
@Override
publicvoidonItemClick(AdapterView>parent,Viewview,
intposition,longid){
//这里可以自由发挥,比如播放一首歌曲等等
}
});
}
} 最后看一下效果:
如果觉得《android listview网络图片 Android ListView从网络获取图片及文字显示》对你有帮助,请点赞、收藏,并留下你的观点哦!