很多情況,我們需要從網絡加載數據,這個時候我們需要異步的方法去加載,並且實現數據緩存到本地的功能。
在主界面定義定義一個listview控件
main.xml代碼
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical" >
- <ListView
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:id="@+id/listView"/>
- </LinearLayout>
在定義listview條目顯示的界面
listview_item.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal" >
- <ImageView
- android:layout_width="120dp"
- android:layout_height="120dp"
- android:id="@+id/imageView"
- />
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textSize="18sp"
- android:textColor="#FFFFFF"
- android:id="@+id/textView"
- />
- </LinearLayout>
自定義適配器類,繼承BaseAdapter
- public class ContactAdapter extends BaseAdapter {
- private List<Contact> data;
- private int listviewItem;
- 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;
- }
- <span style="white-space:pre"> </span>//listview顯示每一個條目都會調用此方法
- <span style="white-space:pre"> </span>//convertView: ListView考慮到性能,會對第一屏的顯示的條目進行緩存
- public View getView(int position, View convertView, ViewGroup parent) {
- ImageView imageView = null;
- TextView textView = null;
- if(convertView == null){
- convertView = layoutInflater.inflate(listviewItem, null);
- 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);
- }
- 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 {
- <span style="white-space:pre"> </span>//得到圖片的uri地址
- 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);
- }
- }
- <span style="white-space:pre"> </span>//數據包裹類,如果顯示一個條目就去查找控件id的話,這樣會很耗性能
- private final class DataWrapper{
- public ImageView imageView;
- public TextView textView;
- public DataWrapper(ImageView imageView, TextView textView) {
- this.imageView = imageView;
- this.textView = textView;
- }
- }
- }
工具類
- public class ContactService {
- /**
- * 獲取聯繫人
- * @return
- */
- public static List<Contact> getContacts() throws Exception{
- String path = "http://192.168.1.100:8080/web/list.xml";
- HttpURLConnection conn = (HttpURLConnection) new URL(path).openConnection();
- conn.setConnectTimeout(5000);
- conn.setRequestMethod("GET");
- if(conn.getResponseCode() == 200){
- return parseXML(conn.getInputStream());
- }
- return null;
- }
- /**
- * 解析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 = 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;
- }
- }
主界面Activity的代碼
- 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.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.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();
- }
- }
注意:由於應用訪問到網絡和sdcard,所以在功能清單文件中需要加入權限
- <uses-permission android:name="android.permission.INTERNET"/>
- <!-- 在SDCard中創建與刪除文件權限 -->
- <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
- <!-- 往SDCard寫入數據權限 -->
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>