Android-搭建簡單服務端+ListView非同步載入資料

來源:互聯網
上載者:User

標籤:android   des   style   blog   class   code   

Android-搭建簡單服務端+ListView非同步載入資料


2014年5月6日

本篇博文帶給大家的是教大家如何在MyEclipse中搭建一個服務端,並通過手機端與其通訊,非同步載入資料。


筆者使用的是MyEclipse,各位也可以直接用Eclipse建立Java Web項目,Google提供的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://192.192.8.233:8080/Test/images/1.gif" /></contact><contact id="2"><name>青蛙2</name><image src="http://192.192.8.233:8080/Test/images/2.gif" /></contact><contact id="3"><name>青蛙3</name><image src="http://192.192.8.233:8080/Test/images/3.gif" /></contact><contact id="4"><name>青蛙4</name><image src="http://192.192.8.233:8080/Test/images/4.gif" /></contact><contact id="5"><name>青蛙5</name><image src="http://192.192.8.233:8080/Test/images/5.gif" /></contact><contact id="6"><name>青蛙6</name><image src="http://192.192.8.233:8080/Test/images/6.gif" /></contact><contact id="7"><name>青蛙7</name><image src="http://192.192.8.233:8080/Test/images/7.gif" /></contact><contact id="8"><name>青蛙8</name><image src="http://192.192.8.233:8080/Test/images/8.gif" /></contact><contact id="9"><name>青蛙9</name><image src="http://192.192.8.233:8080/Test/images/9.gif" /></contact><contact id="10"><name>青蛙10</name><image src="http://192.192.8.233:8080/Test/images/10.gif" /></contact><contact id="11"><name>青蛙11</name><image src="http://192.192.8.233:8080/Test/images/11.gif" /></contact><contact id="12"><name>青蛙12</name><image src="http://192.192.8.233:8080/Test/images/12.gif" /></contact><contact id="13"><name>青蛙13</name><image src="http://192.192.8.233:8080/Test/images/13.gif" /></contact><contact id="14"><name>青蛙14</name><image src="http://192.192.8.233:8080/Test/images/14.gif" /></contact><contact id="15"><name>青蛙15</name><image src="http://192.192.8.233:8080/Test/images/15.gif" /></contact><contact id="16"><name>青蛙16</name><image src="http://192.192.8.233:8080/Test/images/16.gif" /></contact><contact id="17"><name>青蛙17</name><image src="http://192.192.8.233:8080/Test/images/17.gif" /></contact><contact id="18"><name>青蛙18</name><image src="http://192.192.8.233:8080/Test/images/18.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設定許可權:

    <!-- 連網許可權 -->    <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){//串連成功返回碼200return 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字串.jpgFile 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));}};@Overridepublic 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();}@Overrideprotected void onDestroy() {// 刪除緩衝for (File file : cache.listFiles()) {file.delete();}cache.delete();super.onDestroy();}}

這裡我們開了一個線程來載入資料,是因為網路操作不能在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; // 條目idprivate 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;}}}

以上就是本項目所有的代碼,運行項目效果如下:



最後附上服務端和用戶端源碼:http://download.csdn.net/detail/wwj_748/7300567



相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.