在Android开发中我们经常有这样的需求,从服务器上下载xml或者JSON类型的数据,其中包括一些图片资源,本demo模拟了这个需求,从网络上加载XML资源,其中包括图片,我们要做的解析XML里面的数据,并且把图片缓存到本地一个cache目录里面,并且用一个自定义的Adapter去填充到LIstView,demo运行效果见下图:

通过这个demo,要学会有一下几点

1.怎么解析一个XML

2.demo中用到的缓存图片到本地一个临时目录的思想是怎样的?

3.AsyncTask类的使用,因为要去异步的加载数据,就必须开启线程,但是在开启线程的时有时候不能很好的控制线程的数量,线程数量太大的时候手机会很快被卡死 这里就采用AsynsTask类的去解决这个问题,这个类里面封装了线程池的技术,从而保证不会因开启过多的线程而消耗太多的资源

4.本demo中的Handler类的使用情况 5.自定义adapter的使用 

下面是demo中的Activity。

 



    1. public class MainActivity extends Activity {  
    2. protected static final int SUCCESS_GET_CONTACT = 0;  
    3. private ListView mListView;  
    4. private MyContactAdapter mAdapter;  
    5. private File cache;  
    6.       
    7. private Handler mHandler = new Handler(){  
    8. public void handleMessage(android.os.Message msg) {  
    9. if(msg.what == SUCCESS_GET_CONTACT){  
    10.                 List<Contact> contacts = (List<Contact>) msg.obj;  
    11. new MyContactAdapter(getApplicationContext(),contacts,cache);  
    12.                 mListView.setAdapter(mAdapter);  
    13.             }  
    14.         };  
    15.     };  
    16.       
    17. @Override  
    18. public void onCreate(Bundle savedInstanceState) {  
    19. super.onCreate(savedInstanceState);  
    20.         setContentView(R.layout.main);  
    21.           
    22.         mListView = (ListView) findViewById(R.id.listview);  
    23.           
    24. //创建缓存目录,系统一运行就得创建缓存目录的,  
    25. new File(Environment.getExternalStorageDirectory(), "cache");  
    26.           
    27. if(!cache.exists()){  
    28.             cache.mkdirs();  
    29.         }  
    30.           
    31. //获取数据,主UI线程是不能做耗时操作的,所以启动子线程来做  
    32. new Thread(){  
    33. public void run() {  
    34. new ContactService();  
    35. null;  
    36. try {  
    37.                     contacts = service.getContactAll();  
    38. catch (Exception e) {  
    39.                     e.printStackTrace();  
    40.                 }  
    41. //子线程通过Message对象封装信息,并且用初始化好的,  
    42. //Handler对象的sendMessage()方法把数据发送到主线程中,从而达到更新UI主线程的目的  
    43. new Message();  
    44.                 msg.what = SUCCESS_GET_CONTACT;  
    45.                 msg.obj = contacts;  
    46.                 mHandler.sendMessage(msg);  
    47.             };  
    48.         }.start();  
    49.     }  
    50.       
    51. }



    Activity中,注意以下几点,



    1.初始化了一个缓存目录,这个目录最好是应用开启就去创建好,为手续缓存图片做准备,在这里把数据存放在SDCard上



    2.要去服务器加载数据,这个耗时操作最好是去开启线程加载数据,加载完毕后去异步的更新UI线程,利用Handler机制能很好的解决这个问题,



    3.最后退出应用的时候,要删掉缓存目录和目录里面的数据,避免给手机制造很多的垃圾文件



    下面就是一个Service类了,



      1. public class ContactService {  
      2.   
      3. /**
      4.      * 从服务器上获取数据
      5.      */  
      6. public List<Contact> getContactAll() throws Exception {  
      7. null;  
      8. "http://192.168.1.103:8080/myweb/list.xml";  
      9. new URL(Parth);  
      10.         HttpURLConnection conn = (HttpURLConnection) url.openConnection();  
      11. 3000);  
      12. "GET");  
      13. if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {  
      14.             InputStream is = conn.getInputStream();  
      15. // 这里获取数据直接放在XmlPullParser里面解析  
      16.             contacts = xmlParser(is);  
      17. return contacts;  
      18. else {  
      19. return null;  
      20.         }  
      21.     }  
      22.   
      23. // 这里并没有下载图片下来,而是把图片的地址保存下来了  
      24. private List<Contact> xmlParser(InputStream is) throws Exception {  
      25. null;  
      26. null;  
      27.         XmlPullParser parser = Xml.newPullParser();  
      28. "UTF-8");  
      29. int eventType = parser.getEventType();  
      30. while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {  
      31. switch (eventType) {  
      32. case XmlPullParser.START_TAG:  
      33. if (parser.getName().equals("contacts")) {  
      34. new ArrayList<Contact>();  
      35. else if (parser.getName().equals("contact")) {  
      36. new Contact();  
      37. 0)));  
      38. else if (parser.getName().equals("name")) {  
      39.                     contact.setName(parser.nextText());  
      40. else if (parser.getName().equals("image")) {  
      41. 0));  
      42.                 }  
      43. break;  
      44.   
      45. case XmlPullParser.END_TAG:  
      46. if (parser.getName().equals("contact")) {  
      47.                     contacts.add(contact);  
      48.                 }  
      49. break;  
      50.             }  
      51.         }  
      52. return contacts;  
      53.     }  
      54.   
      55. /*
      56.      * 从网络上获取图片,如果图片在本地存在的话就直接拿,如果不存在再去服务器上下载图片
      57.      * 这里的path是图片的地址
      58.      */  
      59. public Uri getImageURI(String path, File cache) throws Exception {  
      60. "."));  
      61. new File(cache, name);  
      62. // 如果图片存在本地缓存目录,则不去服务器下载   
      63. if (file.exists()) {  
      64. return Uri.fromFile(file);//Uri.fromFile(path)这个方法能得到文件的URI  
      65. else {  
      66. // 从网络上获取图片  
      67. new URL(path);  
      68.             HttpURLConnection conn = (HttpURLConnection) url.openConnection();  
      69. 5000);  
      70. "GET");  
      71. true);  
      72. if (conn.getResponseCode() == 200) {  
      73.   
      74.                 InputStream is = conn.getInputStream();  
      75. new FileOutputStream(file);  
      76. byte[] buffer = new byte[1024];  
      77. int len = 0;  
      78. while ((len = is.read(buffer)) != -1) {  
      79. 0, len);  
      80.                 }  
      81.                 is.close();  
      82.                 fos.close();  
      83. // 返回一个URI对象  
      84. return Uri.fromFile(file);  
      85.             }  
      86.         }  
      87. return null;  
      88.     }  
      89. }



      Serivce类中,注意以下几点



      1.HttpURLConnection conn = (HttpURLConnection) url.openConnection();获取一个链接,从而进行通讯 2.怎么利用XxmlPullPaser类去解析XML,从而把数据封装成对象



      3.getImageURI(String path, File cache) 这个方法具体实现



      4.Uri.fromFile(file);这个方法能够直接返回一个Uri来



      下面是自定义的Adapter类,




      1. public class MyContactAdapter extends BaseAdapter {  
      2.   
      3. protected static final int SUCCESS_GET_IMAGE = 0;  
      4. private Context context;  
      5. private List<Contact> contacts;  
      6. private File cache;  
      7. private LayoutInflater mInflater;  
      8.   
      9. // 自己定义的构造函数  
      10. public MyContactAdapter(Context context, List<Contact> contacts, File cache) {  
      11. this.context = context;  
      12. this.contacts = contacts;  
      13. this.cache = cache;  
      14.   
      15.         mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
      16.     }  
      17.   
      18. @Override  
      19. public int getCount() {  
      20. return contacts.size();  
      21.     }  
      22.   
      23. @Override  
      24. public Object getItem(int position) {  
      25. return contacts.get(position);  
      26.     }  
      27.   
      28. @Override  
      29. public long getItemId(int position) {  
      30. return position;  
      31.     }  
      32.   
      33. @Override  
      34. public View getView(int position, View convertView, ViewGroup parent) {  
      35. // 1获取item,再得到控件  
      36. // 2 获取数据  
      37. // 3绑定数据到item  
      38. null;  
      39. if (convertView != null) {  
      40.             view = convertView;  
      41. else {  
      42. null);  
      43.         }  
      44.   
      45.         ImageView iv_header = (ImageView) view.findViewById(R.id.iv_header);  
      46.         TextView tv_name = (TextView) view.findViewById(R.id.tv_name);  
      47.   
      48.         Contact contact = contacts.get(position);  
      49.   
      50. // 异步的加载图片 (线程池 + Handler ) ---> AsyncTask  
      51.         asyncloadImage(iv_header, contact.image);  
      52.         tv_name.setText(contact.name);  
      53.   
      54. return view;  
      55.     }  
      56.   
      57. private void asyncloadImage(ImageView iv_header, String path) {  
      58. new ContactService();  
      59. new AsyncImageTask(service, iv_header);  
      60.         task.execute(path);  
      61.     }  
      62.   
      63. private final class AsyncImageTask extends AsyncTask<String, Integer, Uri> {  
      64.   
      65. private ContactService service;  
      66. private ImageView iv_header;  
      67.   
      68. public AsyncImageTask(ContactService service, ImageView iv_header) {  
      69. this.service = service;  
      70. this.iv_header = iv_header;  
      71.         }  
      72.   
      73. // 后台运行的子线程子线程  
      74. @Override  
      75. protected Uri doInBackground(String... params) {  
      76. try {  
      77. return service.getImageURI(params[0], cache);  
      78. catch (Exception e) {  
      79.                 e.printStackTrace();  
      80.             }  
      81. return null;  
      82.         }  
      83.   
      84. // 这个放在在ui线程中执行  
      85. @Override  
      86. protected void onPostExecute(Uri result) {  
      87. super.onPostExecute(result);   
      88. // 完成图片的绑定  
      89. if (iv_header != null && result != null) {  
      90.                 iv_header.setImageURI(result);  
      91.             }  
      92.         }  
      93.     }  
      94.   
      95. /**
      96.      * 采用普通方式异步的加载图片
      97.      */  
      98. /*private void asyncloadImage(final ImageView iv_header, final String path) {
      99.         final Handler mHandler = new Handler() {
      100.             @Override
      101.             public void handleMessage(Message msg) {
      102.                 super.handleMessage(msg);
      103.                 if (msg.what == SUCCESS_GET_IMAGE) {
      104.                     Uri uri = (Uri) msg.obj;
      105.                     if (iv_header != null && uri != null) {
      106.                         iv_header.setImageURI(uri);
      107.                     }
      108. 
      109.                 }
      110.             }
      111.         };
      112.         // 子线程,开启子线程去下载或者去缓存目录找图片,并且返回图片在缓存目录的地址
      113.         Runnable runnable = new Runnable() {
      114.             @Override
      115.             public void run() {
      116.                 ContactService service = new ContactService();
      117.                 try {
      118.                     //这个URI是图片下载到本地后的缓存目录中的URI
      119.                     Uri uri = service.getImageURI(path, cache);
      120.                     Message msg = new Message();
      121.                     msg.what = SUCCESS_GET_IMAGE;
      122.                     msg.obj = uri;
      123.                     mHandler.sendMessage(msg);
      124.                 } catch (Exception e) {
      125.                     e.printStackTrace();
      126.                 }
      127.             }
      128.         };
      129.         new Thread(runnable).start();
      130.     }*/  
      131. }



      自定义Adapter中,我们要注意 AsyncImageTask这个类继承了AsyncTask类,AsyncTask是Android中常用来做异步任务的类,对线程池进行了封装。