Android-搭建简单服务端+ListView异步加载数据

本篇博文带给大家的是教大家如何在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文件,内容如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
<!--?xml version= "1.0" encoding= "UTF-8" ?-->
<contacts>
 
     <contact id= "1" >
         <name>青蛙 1 </name>
         <img src= "" style= "display: none;" ><img alt= "加载中..." title= "图片加载中..." src= "http://www.2cto.com/statics/images/s_nopic.gif" >
     </contact>
     <contact id= "2" >
         <name>青蛙 2 </name>
         <img src= "" style= "display: none;" ><img alt= "加载中..." title= "图片加载中..." src= "http://www.2cto.com/statics/images/s_nopic.gif" >
     </contact>
     <contact id= "3" >
         <name>青蛙 3 </name>
         <img src= "" style= "display: none;" ><img alt= "加载中..." title= "图片加载中..." src= "http://www.2cto.com/statics/images/s_nopic.gif" >
     </contact>
     <contact id= "4" >
         <name>青蛙 4 </name>
         <img src= "" style= "display: none;" ><img alt= "加载中..." title= "图片加载中..." src= "http://www.2cto.com/statics/images/s_nopic.gif" >
     </contact>
     <contact id= "5" >
         <name>青蛙 5 </name>
         <img src= "" style= "display: none;" ><img alt= "加载中..." title= "图片加载中..." src= "http://www.2cto.com/statics/images/s_nopic.gif" >
     </contact>
     <contact id= "6" >
         <name>青蛙 6 </name>
         <img src= "" style= "display: none;" ><img alt= "加载中..." title= "图片加载中..." src= "http://www.2cto.com/statics/images/s_nopic.gif" >
     </contact>
     <contact id= "7" >
         <name>青蛙 7 </name>
         <img src= "" style= "display: none;" ><img alt= "加载中..." title= "图片加载中..." src= "http://www.2cto.com/statics/images/s_nopic.gif" >
     </contact>
     <contact id= "8" >
         <name>青蛙 8 </name>
         <img src= "" style= "display: none;" ><img alt= "加载中..." title= "图片加载中..." src= "http://www.2cto.com/statics/images/s_nopic.gif" >
     </contact>
     <contact id= "9" >
         <name>青蛙 9 </name>
         <img src= "" style= "display: none;" ><img alt= "加载中..." title= "图片加载中..." src= "http://www.2cto.com/statics/images/s_nopic.gif" >
     </contact>
     <contact id= "10" >
         <name>青蛙 10 </name>
         <img src= "" style= "display: none;" ><img alt= "加载中..." title= "图片加载中..." src= "http://www.2cto.com/statics/images/s_nopic.gif" >
     </contact>
     <contact id= "11" >
         <name>青蛙 11 </name>
         <img src= "" style= "display: none;" ><img alt= "加载中..." title= "图片加载中..." src= "http://www.2cto.com/statics/images/s_nopic.gif" >
     </contact>
     <contact id= "12" >
         <name>青蛙 12 </name>
         <img src= "" style= "display: none;" ><img alt= "加载中..." title= "图片加载中..." src= "http://www.2cto.com/statics/images/s_nopic.gif" >
     </contact>
     <contact id= "13" >
         <name>青蛙 13 </name>
         <img src= "" style= "display: none;" ><img alt= "加载中..." title= "图片加载中..." src= "http://www.2cto.com/statics/images/s_nopic.gif" >
     </contact>
     <contact id= "14" >
         <name>青蛙 14 </name>
         <img src= "" style= "display: none;" ><img alt= "加载中..." title= "图片加载中..." src= "http://www.2cto.com/statics/images/s_nopic.gif" >
     </contact>
     <contact id= "15" >
         <name>青蛙 15 </name>
         <img src= "" style= "display: none;" ><img alt= "加载中..." title= "图片加载中..." src= "http://www.2cto.com/statics/images/s_nopic.gif" >
     </contact>
     <contact id= "16" >
         <name>青蛙 16 </name>
         <img src= "" style= "display: none;" ><img alt= "加载中..." title= "图片加载中..." src= "http://www.2cto.com/statics/images/s_nopic.gif" >
     </contact>
     <contact id= "17" >
         <name>青蛙 17 </name>
         <img src= "" style= "display: none;" ><img alt= "加载中..." title= "图片加载中..." src= "http://www.2cto.com/statics/images/s_nopic.gif" >
     </contact>
     <contact id= "18" >
         <name>青蛙 18 </name>
         <img src= "" style= "display: none;" ><img alt= "加载中..." title= "图片加载中..." src= "http://www.2cto.com/statics/images/s_nopic.gif" >
     </contact>
 
</contacts>

我们可以看到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设置权限:

?
1
2
<!-- 联网权限 -->
<uses-permission android:name= "android.permission.INTERNET" ></uses-permission>

根据服务端list.xml,我们需要定义一个实体类:

/07_DataAsyncLoad/src/com/wwj/domain/Contact.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
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 ;
     }
 
}
</contact></contact></contact></contact>

上面代码已经很清楚的定义了获取服务端数据的方法,大致流程是这样的:传递一个网络路径path,通过URL打开连接,通过HttpURLConnection连接服务端,得到输入流,解析xml文件再获得数据。


上面代码获取网络图片,需要进行MD5加密计算,具体方法如下:

/07_DataAsyncLoad/src/com/wwj/utils/MD5.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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 = ContactService.getContacts();
                     // 通过handler来发送消息
                     handler.sendMessage(handler.obtainMessage( 22 , data));
                 } catch (Exception e) {
                     e.printStackTrace();
                 }
             }
         }).start();
     }
 
     @Override
     protected void onDestroy() {
         // 删除缓存
         for (File file : cache.listFiles()) {
             file.delete();
         }
         cache.delete();
         super .onDestroy();
     }
 
}</contact></contact>

这里我们开了一个线程来加载数据,是因为网络操作不能在UI线程中进行,加载完数据后通过Hanlder发送消息,显示列表。


一般情况下,我们获取图片需要另外处理,我们有很多种方法,最常用的就是Handler+Thread和AsyncTask两种,具体实现来看:

/07_DataAsyncLoad/src/com/wwj/adapter/ContactAdapter.java

我们定义了一个列表适配器,用来填充我们的数据,我们的图片异步加载也在这里实现了:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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 = data;
         this .listviewItem = listviewItem;
         this .cache = cache;
         layoutInflater = (LayoutInflater) context
                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE); // 获取布局填充服务
     }
 
     /**
      * 得到数据的总数
      */
     public int getCount() {
         return data.size();
     }
 
     /**
      * 根据数据索引得到集合所对应的数据
      */
     public Object getItem( int position) {
         return data.get(position);
     }
 
     public long getItemId( int position) {
         return position;
     }
 
     /**
      * 当listView每显示一个条目的时候,都会调用这个方法
      */
     public View getView( int position, View convertView, ViewGroup parent) {
         ImageView imageView = null ;
         TextView textView = null ;
 
         if (convertView == null ) {
             convertView = layoutInflater.inflate(listviewItem, null ); // 获取条目的view对象
             imageView = (ImageView) convertView.findViewById(R.id.imageView);
             textView = (TextView) convertView.findViewById(R.id.textView);
             convertView.setTag( new DataWrapper(imageView, textView));
         } else {
             DataWrapper dataWrapper = (DataWrapper) convertView.getTag();
             imageView = dataWrapper.imageView;
             textView = dataWrapper.textView;
         }
         Contact contact = data.get(position);
         textView.setText(contact.name);
         asyncImageLoad(imageView, contact.image);
         return convertView;
     }
 
     private void asyncImageLoad(ImageView imageView, String path) {
         AsyncImageTask asyncImageTask = new AsyncImageTask(imageView);
         asyncImageTask.execute(path);
 
     }
 
     /**
      * 使用AsyncTask异步加载图片
      *
      * @author Administrator
      *
      */
     private final class AsyncImageTask extends AsyncTask<string, integer,= "" uri= "" > {
         private ImageView imageView;
 
         public AsyncImageTask(ImageView imageView) {
             this .imageView = imageView;
         }
 
         protected Uri doInBackground(String... params) { // 子线程中执行的
             try {
                 return ContactService.getImage(params[ 0 ], cache);
             } catch (Exception e) {
                 e.printStackTrace();
             }
             return null ;
         }
 
         protected void onPostExecute(Uri result) { // 运行在主线程
             if (result != null && imageView != null )
                 imageView.setImageURI(result);
         }
     }
 
     // 使用Handler进行异步加载图片
     /*
      * private void asyncImageLoad(final ImageView imageView, final String path)
      * {
      *  final Handler handler = new Handler(){
      *   public void
      *      handleMessage(Message msg) {//运行在主线程中
      *      Uri uri = (Uri)msg.obj;
      *      if(uri!=null && imageView!= null) imageView.setImageURI(uri);
      *  }
      *  };
      *
      * Runnable runnable = new Runnable() {
      *  public void run() {
      *   try {
      *    Uri uri =
      *          ContactService.getImage(path, cache);
      *      handler.sendMessage(handler.obtainMessage(10, uri));
      *  } catch (Exception e) {
      *      e.printStackTrace();
      *   }
      *  }
      *  };
      *   new Thread(runnable).start();
      *  }
      */
     private final class DataWrapper {
         public ImageView imageView;
         public TextView textView;
 
         public DataWrapper(ImageView imageView, TextView textView) {
             this .imageView = imageView;
             this .textView = textView;
         }
     }
}
</string,></contact></contact>

源码:http://download.youkuaiyun.com/detail/wwj_748/7300567


原文出处:http://www.2cto.com/kf/201405/298719.html


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值