首页 > 代码库 > Android-搭建简单服务端+ListView异步加载数据
Android-搭建简单服务端+ListView异步加载数据
Android-搭建简单服务端+ListView异步加载数据
2014年5月6日
本篇博文带给大家的是教大家如何在MyEclipse中搭建一个服务端,并通过手机端与其通信,异步加载数据。
笔者使用的是MyEclipse,各位也可以直接用Eclipse创建Java Web项目,谷歌提供的ADT Bundle是不能创建Web项目,读者可以下载Eclipse For JaveEE Developer这个IDE。
下面来介绍如何在MyEclipse创建一个Web项目,并部署到Tomcat当中,关于Tomcat的配置笔者在这里就不多说了。
创建一个名为Test的Web项目,项目结构如下图所示:
我创建了一个images文件夹和list.xml文件,images文件夹存放的是一些图片,是我们下面要获取的,list.xml是一个xml文件,内容如下:
<?xml version="1.0" encoding="UTF-8"?> <contacts> <contact id="1"> <name>青蛙1</name> <image src=http://www.mamicode.com/"http://192.192.8.233:8080/Test/images/1.gif" />>我们可以看到list.xml最外层是一个contacts标签,里面有多个子contact标签,每个子标签包含id、name和image内容,这就是我们下面要解析的内容对应每一个Contact对象。
这里要提一下,我们看到image标签,src是图片url地址,这个地址是我PC的IP地址,读者在测试的时候需要将这个IP地址改为你的PC的IP地址,如何得到?运行->cmd->ipconfig /all查看ipv4地址,就是你电脑的ip地址了。
创建好Web项目之后,我们在电脑上测试一下,在浏览器输入地址:
http://192.192.8.233:8080/Test/list.xml
看到以上内容,说明我们已经可以访问到我们的服务端了,下面我们就可以开发我们的客户端:
我这里创建了一个07_DataAsyncLoad的项目:
目录结构如下:
因为需要联网,在AndroidManifest.xml设置权限:
<!-- 联网权限 --> <uses-permission android:name="android.permission.INTERNET" />
根据服务端list.xml,我们需要定义一个实体类:/07_DataAsyncLoad/src/com/wwj/domain/Contact.java
package com.wwj.domain; /** * 联系人实体类 * * @author wwj * */ public class Contact { public int id; public String name; public String image; public Contact(int id, String name, String image) { this.id = id; this.name = name; this.image = image; } public Contact() { } }
需要访问服务端并且解析xml文件,我们定义一个服务类:/07_DataAsyncLoad/src/com/wwj/service/ContactService.java
package com.wwj.service; import java.io.File; import java.io.FileOutputStream; 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 com.wwj.domain.Contact; import com.wwj.utils.MD5; import android.net.Uri; import android.util.Xml; public class ContactService { /** * 获取联系人 * @return */ public static List<Contact> getContacts() throws Exception{ // 服务器文件路径 String path = "http://192.192.8.233:8080/Test/list.xml"; HttpURLConnection conn = (HttpURLConnection) new URL(path).openConnection(); conn.setConnectTimeout(5000); //设置超时5秒 conn.setRequestMethod("GET"); //设置请求方式 if(conn.getResponseCode() == 200){ //连接成功返回码200 return parseXML(conn.getInputStream()); } return null; } /** * 利用pull解析器对xml文件进行解析 * @param xml * @return * @throws Exception */ private static List<Contact> parseXML(InputStream xml) throws Exception{ List<Contact> contacts = new ArrayList<Contact>(); Contact contact = null; XmlPullParser pullParser = Xml.newPullParser(); pullParser.setInput(xml, "UTF-8"); int event = pullParser.getEventType(); //取得开始文档语法 while(event != XmlPullParser.END_DOCUMENT){ //只要不等于文档结束事件,循环解析 switch (event) { case XmlPullParser.START_TAG: //开始标签 if("contact".equals(pullParser.getName())){ contact = new Contact(); contact.id = new Integer(pullParser.getAttributeValue(0)); }else if("name".equals(pullParser.getName())){ contact.name = pullParser.nextText(); //取得后面节点的文本值 }else if("image".equals(pullParser.getName())){ contact.image = pullParser.getAttributeValue(0); //取得第一个属性的值 } break; case XmlPullParser.END_TAG: //结束标签 if("contact".equals(pullParser.getName())){ contacts.add(contact); //将contact对象添加到集合中 contact = null; } break; } event = pullParser.next(); //去下一个标签 } return contacts; } /** * 获取网络图片,如果图片存在于缓存中,就返回该图片,否则从网络中加载该图片并缓存起来 * @param path 图片路径 * @return */ public static Uri getImage(String path, File cacheDir) throws Exception{// path -> MD5 ->32字符串.jpg File localFile = new File(cacheDir, MD5.getMD5(path)+ path.substring(path.lastIndexOf("."))); if(localFile.exists()){ return Uri.fromFile(localFile); }else{ HttpURLConnection conn = (HttpURLConnection) new URL(path).openConnection(); conn.setConnectTimeout(5000); conn.setRequestMethod("GET"); if(conn.getResponseCode() == 200){ FileOutputStream outStream = new FileOutputStream(localFile); InputStream inputStream = conn.getInputStream(); byte[] buffer = new byte[1024]; int len = 0; while( (len = inputStream.read(buffer)) != -1){ outStream.write(buffer, 0, len); } inputStream.close(); outStream.close(); return Uri.fromFile(localFile); } } return null; } }
上面代码已经很清楚的定义了获取服务端数据的方法,大致流程是这样的:传递一个网络路径path,通过URL打开连接,通过HttpURLConnection连接服务端,得到输入流,解析xml文件再获得数据。
上面代码获取网络图片,需要进行MD5加密计算,具体方法如下:
/07_DataAsyncLoad/src/com/wwj/utils/MD5.java
package com.wwj.utils; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class MD5 { /** * MD5加密算法 * * @param content * @return */ public static String getMD5(String content) { try { MessageDigest digest = MessageDigest.getInstance("MD5"); digest.update(content.getBytes()); return getHashString(digest); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return null; } /** * 获得哈希字符串 * * @param digest * @return */ private static String getHashString(MessageDigest digest) { StringBuilder builder = new StringBuilder(); for (byte b : digest.digest()) { builder.append(Integer.toHexString((b >> 4) & 0xf)); builder.append(Integer.toHexString(b & 0xf)); } return builder.toString(); } }
好,这样我们的服务类就已经写完了,这时我们在MainActivity进行异步加载数据:/07_DataAsyncLoad/src/com/wwj/asyntask/MainActivity.java
package com.wwj.asyntask; import java.io.File; import java.util.List; import com.wwj.adapter.ContactAdapter; import com.wwj.asyntask.R; import com.wwj.domain.Contact; import com.wwj.service.ContactService; import android.app.Activity; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.widget.ListView; public class MainActivity extends Activity { ListView listView; File cache; // 缓存文件 Handler handler = new Handler() { public void handleMessage(Message msg) { listView.setAdapter(new ContactAdapter(MainActivity.this, (List<Contact>) msg.obj, R.layout.listview_item, cache)); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); listView = (ListView) this.findViewById(R.id.listView); cache = new File(Environment.getExternalStorageDirectory(), "cache"); // 实例化缓存文件 if (!cache.exists()) cache.mkdirs(); // 如果文件不存在,创建 // 开一个线程来加载数据 new Thread(new Runnable() { public void run() { try { List<Contact> data = http://www.mamicode.com/ContactService.getContacts();>
这里我们开了一个线程来加载数据,是因为网络操作不能在UI线程中进行,加载完数据后通过Hanlder发送消息,显示列表。
一般情况下,我们获取图片需要另外处理,我们有很多种方法,最常用的就是Handler+Thread和AsyncTask两种,具体实现来看:
/07_DataAsyncLoad/src/com/wwj/adapter/ContactAdapter.java
我们定义了一个列表适配器,用来填充我们的数据,我们的图片异步加载也在这里实现了:
package com.wwj.adapter; import java.io.File; import java.util.List; import android.content.Context; import android.net.Uri; import android.os.AsyncTask; 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.wwj.asyntask.R; import com.wwj.domain.Contact; import com.wwj.service.ContactService; /** * 自定义适配器 * * @author wwj * */ public class ContactAdapter extends BaseAdapter { private List<Contact> data; // 缓存数据 private int listviewItem; // 条目id private File cache; // 缓存文件 LayoutInflater layoutInflater; public ContactAdapter(Context context, List<Contact> data, int listviewItem, File cache) { this.data = http://www.mamicode.com/data;>
以上就是本项目所有的代码,运行项目效果如下:
最后附上服务端和客户端源码:http://download.csdn.net/detail/wwj_748/7300567