編輯:關於Android編程
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文件,內容如下:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD48cD48cHJlIGNsYXNzPQ=="brush:java;">
我們可以看到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設置權限:
/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() { } }
/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 ListgetContacts() 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 parseXML(InputStream xml) throws Exception{ List contacts = new ArrayList (); 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; } }
上面代碼獲取網絡圖片,需要進行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(); } }
/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) 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 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(); } }
一般情況下,我們獲取圖片需要另外處理,我們有很多種方法,最常用的就是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 Listdata; // 緩存數據 private int listviewItem; // 條目id private File cache; // 緩存文件 LayoutInflater layoutInflater; public ContactAdapter(Context context, List 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 { 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
Android快捷方式解密Android快捷方式作為Android設備的殺手锏技能,一直都是非常重要的一個功能,也正是如此,各種流氓App也不斷通過快捷方式霸占著這樣一個
內存洩漏基本概念內存檢測這部分,相關的知識有JVM虛擬機垃圾收集機制,類加載機制,內存模型等。編寫沒有內存洩漏的程序,對提高程序穩定性,提高用戶體驗具有重要的意義。因此,
本章目標 掌握單選按鈕的用法 掌握復選框的用法 掌握開關按鈕的用法 掌握圖像視圖的用法。 掌握自動完成文本框的用法。單選控件——RadioButt
怎樣才能寫出優秀的Android App,是每一個程序員追求的目標。那麼怎麼才能寫出一個優秀的App呢?相信很多初學者也會有這種迷茫。一句話來回答這個問題:細節很重要。今