android 异步方式实现数据加载

来源:互联网 发布:mv 文件夹 linux 编辑:程序博客网 时间:2024/05/13 23:54

使用AsyncTask实现异步处理

由于主线程(也可叫UI线程)负责处理用户输入事件(点击按钮、触摸屏幕、按键等),如果主线程被阻塞,应用就会报ANR错误。为了不阻塞主线程,我们需要在子线程中处理耗时的操作,在处理耗时操作的过程中,子线程可能需要更新UI控件的显示,由于UI控件的更新重绘是由主线程负责的,所以子线程需要通过Handler发送消息给主线程的消息队列,由运行在主线程的消息处理代码接收消息后更新UI控件的显示。

采用线程+Handler实现异步处理时,当每次执行耗时操作都创建一条新线程进行处理,性能开销会比较大。另外,如果耗时操作执行的时间比较长,就有可能同时运行着许多线程,系统将不堪重负。为了提高性能,我们可以使用AsynTask实现异步处理,事实上其内部也是采用线程+Handler来实现异步处理的,只不过是其内部使用了线程池技术,有效的降低了线程创建数量及限定了同时运行的线程数。

  private final class AsyncImageTask extends AsyncTask<String, Integer, String>{

        protectedvoid onPreExecute(){ //运行在UI线程

        }

        protectedStringdoInBackground(String...params) {//在子线程中执行

            return“itcast”;

        }

        protectedvoid onPostExecute(String result) {//运行在UI线程

        }  

        protectedvoid onProgressUpdate(Integer… values) {//运行在UI线程

        }  

   }

AsyncTask<String, Integer, String>中定义的三个泛型参数分别用作了doInBackground、onProgressUpdate的输入方法类型,第三个参数用作了doInBackground的返回参数类型和onPostExecute的输入参数类型。

AsyncTask定义了三种泛型类型Params,Progress和Result。

  • Params 启动任务执行的输入参数,比如HTTP请求的URL。
  • Progress 后台任务执行的百分比。
  • Result 后台执行任务最终返回的结果,比如String。

使用AsyncTask异步加载数据最少要重写以下这两个方法:

  • doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。
  • onPostExecute(Result)  相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回

有必要的话还得重写以下这三个方法,但不是必须的:

  • onProgressUpdate(Progress…)   可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。
  • onPreExecute() 这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。
  • onCancelled()用户调用取消时,要做的操作

使用AsyncTask类,以下是几条必须遵守的准则:

  • Task的实例必须在UI thread中创建;
  • execute方法必须在UI thread中调用;
  • 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法;
  • 该task只能被执行一次,否则多次调用时将会出现异常;
下面是看代码中是如何使用的

1、Contact.java创建数据对象类

[html] view plain copy
  1. package cn.org.domain;  
  2.   
  3. public class Contact {  
  4.     public int id;  
  5.     public String name;  
  6.     public String image;  
  7.     public Contact(int id, String name, String image) {  
  8.         this.id = id;  
  9.         this.name = name;  
  10.         this.image = image;  
  11.     }  
  12.     public Contact(){}  
  13. }  

2.这里我们首先需要准备好数据,是通过解析web service中的xml数据,数据是通过MD5进行加密的ContactService.java

[html] view plain copy
  1. package cn.itcast.service;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileOutputStream;  
  5. import java.io.InputStream;  
  6. import java.net.HttpURLConnection;  
  7. import java.net.URL;  
  8. import java.util.ArrayList;  
  9. import java.util.List;  
  10.   
  11. import org.xmlpull.v1.XmlPullParser;  
  12.   
  13. import android.net.Uri;  
  14. import android.util.Xml;  
  15.   
  16. import cn.org.domain.Contact;  
  17. import cn.org.utils.MD5;  
  18.   
  19. public class ContactService {  
  20.   
  21.     /**  
  22.      * 获取联系人  
  23.      * @return  
  24.      */  
  25.     public static List<Contact> getContacts() throws Exception{  
  26.         String path = "http://192.168.1.100:8080/web/list.xml";  
  27.         HttpURLConnection conn = (HttpURLConnection) new URL(path).openConnection();  
  28.         conn.setConnectTimeout(5000);  
  29.         conn.setRequestMethod("GET");  
  30.         if(conn.getResponseCode() == 200){  
  31.             return parseXML(conn.getInputStream());  
  32.         }  
  33.         return null;  
  34.     }  
  35.   
  36.     private static List<Contact> parseXML(InputStream xml) throws Exception{  
  37.         List<Contact> contacts = new ArrayList<Contact>();  
  38.         Contact contact = null;  
  39.         XmlPullParser pullParser = Xml.newPullParser();  
  40.         pullParser.setInput(xml, "UTF-8");  
  41.         int event = pullParser.getEventType();  
  42.         while(event != XmlPullParser.END_DOCUMENT){  
  43.             switch (event) {  
  44.             case XmlPullParser.START_TAG:  
  45.                 if("contact".equals(pullParser.getName())){  
  46.                     contact = new Contact();  
  47.                     contact.id = new Integer(pullParser.getAttributeValue(0));  
  48.                 }else if("name".equals(pullParser.getName())){  
  49.                     contact.name = pullParser.nextText();  
  50.                 }else if("image".equals(pullParser.getName())){  
  51.                     contact.image = pullParser.getAttributeValue(0);  
  52.                 }  
  53.                 break;  
  54.   
  55.             case XmlPullParser.END_TAG:  
  56.                 if("contact".equals(pullParser.getName())){  
  57.                     contacts.add(contact);  
  58.                     contact = null;  
  59.                 }  
  60.                 break;  
  61.             }  
  62.             event = pullParser.next();  
  63.         }  
  64.         return contacts;  
  65.     }  
  66.     /**  
  67.      * 获取网络图片,如果图片存在于缓存中,就返回该图片,否则从网络中加载该图片并缓存起来  
  68.      * @param path 图片路径  
  69.      * @return  
  70.      */  
  71.     public static Uri getImage(String path, File cacheDir) throws Exception{// path -> MD5 ->32字符串.jpg  
  72.         File localFile = new File(cacheDir, MD5.getMD5(path)+ path.substring(path.lastIndexOf(".")));  
  73.         if(localFile.exists()){  
  74.             return Uri.fromFile(localFile);  
  75.         }else{  
  76.             HttpURLConnection conn = (HttpURLConnection) new URL(path).openConnection();  
  77.             conn.setConnectTimeout(5000);  
  78.             conn.setRequestMethod("GET");  
  79.             if(conn.getResponseCode() == 200){  
  80.                 FileOutputStream outStream = new FileOutputStream(localFile);  
  81.                 InputStream inputStream = conn.getInputStream();  
  82.                 byte[] buffer = new byte[1024];  
  83.                 int len = 0;  
  84.                 while( (len = inputStream.read(buffer)) != -1){  
  85.                     outStream.write(buffer, 0, len);  
  86.                 }  
  87.                 inputStream.close();  
  88.                 outStream.close();  
  89.                 return Uri.fromFile(localFile);  
  90.             }  
  91.         }  
  92.         return null;  
  93.     }  
  94.   
  95. }  

[html] view plain copy
  1. package cn.org.utils;  
  2.   
  3. import java.security.MessageDigest;  
  4. import java.security.NoSuchAlgorithmException;  
  5.   
  6. public class MD5 {  
  7.   
  8.     public static String getMD5(String content) {  
  9.         try {  
  10.             MessageDigest digest = MessageDigest.getInstance("MD5");  
  11.             digest.update(content.getBytes());  
  12.             return getHashString(digest);  
  13.               
  14.         } catch (NoSuchAlgorithmException e) {  
  15.             e.printStackTrace();  
  16.         }  
  17.         return null;  
  18.     }  
  19.       
  20.     private static String getHashString(MessageDigest digest) {  
  21.         StringBuilder builder = new StringBuilder();  
  22.         for (byte b : digest.digest()) {  
  23.             builder.append(Integer.toHexString((b >> 4) & 0xf));  
  24.             builder.append(Integer.toHexString(b & 0xf));  
  25.         }  
  26.         return builder.toString();  
  27.     }  
  28. }  

3.ContactAdapter.java 我们来适配绑定数据,这里我们通过异步方式实现

[html] view plain copy
  1. package cn.org.adapter;  
  2.   
  3. import java.io.File;  
  4. import java.util.List;  
  5.   
  6. import cn.org.asyncload.R;  
  7. import cn.org.domain.Contact;  
  8. import cn.org.service.ContactService;  
  9. import android.content.Context;  
  10. import android.net.Uri;  
  11. import android.os.AsyncTask;  
  12. import android.os.Handler;  
  13. import android.os.Message;  
  14. import android.view.LayoutInflater;  
  15. import android.view.View;  
  16. import android.view.ViewGroup;  
  17. import android.widget.BaseAdapter;  
  18. import android.widget.ImageView;  
  19. import android.widget.TextView;  
  20.   
  21. public class ContactAdapter extends BaseAdapter {  
  22.     private List<Contact> data;  
  23.     private int listviewItem;  
  24.     private File cache;  
  25.     LayoutInflater layoutInflater;  
  26.       
  27.     public ContactAdapter(Context context, List<Contact> data, int listviewItem, File cache) {  
  28.         this.data = data;  
  29.         this.listviewItem = listviewItem;  
  30.         this.cache = cache;  
  31.         layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
  32.     }  
  33.     /**  
  34.      * 得到数据的总数  
  35.      */  
  36.     public int getCount() {  
  37.         return data.size();  
  38.     }  
  39.     /**  
  40.      * 根据数据索引得到集合所对应的数据  
  41.      */  
  42.     public Object getItem(int position) {  
  43.         return data.get(position);  
  44.     }  
  45.       
  46.     public long getItemId(int position) {  
  47.         return position;  
  48.     }  
  49.   
  50.     public View getView(int position, View convertView, ViewGroup parent) {  
  51.         ImageView imageView = null;  
  52.         TextView textView = null;  
  53.           
  54.         if(convertView == null){  
  55.             convertView = layoutInflater.inflate(listviewItem, null);  
  56.             imageView = (ImageView) convertView.findViewById(R.id.imageView);  
  57.             textView = (TextView) convertView.findViewById(R.id.textView);  
  58.             convertView.setTag(new DataWrapper(imageView, textView));  
  59.         }else{  
  60.             DataWrapper dataWrapper = (DataWrapper) convertView.getTag();  
  61.             imageView = dataWrapper.imageView;  
  62.             textView = dataWrapper.textView;      
  63.         }  
  64.         Contact contact = data.get(position);  
  65.         textView.setText(contact.name);  
  66.         asyncImageLoad(imageView, contact.image);  
  67.         return convertView;  
  68.     }  
  69.     private void asyncImageLoad(ImageView imageView, String path) {  
  70.         AsyncImageTask asyncImageTask = new AsyncImageTask(imageView);  
  71.         asyncImageTask.execute(path);  
  72.           
  73.     }  
  74.       
  75.     private final class AsyncImageTask extends AsyncTask<String, Integer, Uri>{  
  76.         private ImageView imageView;  
  77.         public AsyncImageTask(ImageView imageView) {  
  78.             this.imageView = imageView;  
  79.         }  
  80.         protected Uri doInBackground(String... params) {//子线程中执行的  
  81.             try {  
  82.                 return ContactService.getImage(params[0], cache);  
  83.             } catch (Exception e) {  
  84.                 e.printStackTrace();  
  85.             }  
  86.             return null;  
  87.         }  
  88.         protected void onPostExecute(Uri result) {//运行在主线程  
  89.             if(result!=null && imageView!= null)  
  90.                 imageView.setImageURI(result);  
  91.         }     
  92.     }  
  93.   
  94.     private final class DataWrapper{  
  95.         public ImageView imageView;  
  96.         public TextView textView;  
  97.         public DataWrapper(ImageView imageView, TextView textView) {  
  98.             this.imageView = imageView;  
  99.             this.textView = textView;  
  100.         }  
  101.     }  
  102. }  
4.MainActivity.java

[html] view plain copy
  1. package cn.org.asyncload;  
  2.   
  3. import java.io.File;  
  4. import java.util.List;  
  5.   
  6. import cn.org.adapter.ContactAdapter;  
  7. import cn.org.domain.Contact;  
  8. import cn.org.service.ContactService;  
  9. import android.app.Activity;  
  10. import android.os.Bundle;  
  11. import android.os.Environment;  
  12. import android.os.Handler;  
  13. import android.os.Message;  
  14. import android.widget.ListView;  
  15.   
  16. public class MainActivity extends Activity {  
  17.     ListView listView;  
  18.     File cache;  
  19.       
  20.     Handler handler = new Handler(){  
  21.         public void handleMessage(Message msg) {  
  22.              listView.setAdapter(new ContactAdapter(MainActivity.this, (List<Contact>)msg.obj,   
  23.                      R.layout.listview_item, cache));  
  24.         }         
  25.     };  
  26.       
  27.     @Override  
  28.     public void onCreate(Bundle savedInstanceState) {  
  29.         super.onCreate(savedInstanceState);  
  30.         setContentView(R.layout.main);  
  31.         listView = (ListView) this.findViewById(R.id.listView);  
  32.           
  33.         cache = new File(Environment.getExternalStorageDirectory(), "cache");  
  34.         if(!cache.exists()) cache.mkdirs();  
  35.           
  36.         new Thread(new Runnable() {           
  37.             public void run() {  
  38.                 try {  
  39.                     List<Contact> data = ContactService.getContacts();  
  40.                     handler.sendMessage(handler.obtainMessage(22, data));  
  41.                 } catch (Exception e) {  
  42.                     e.printStackTrace();  
  43.                 }  
  44.             }  
  45.         }).start();         
  46.     }  
  47.   
  48.     @Override  
  49.     protected void onDestroy() {  
  50.         for(File file : cache.listFiles()){  
  51.             file.delete();  
  52.         }  
  53.         cache.delete();  
  54.         super.onDestroy();  
  55.     }  
  56.       
  57. }  


5.listview_item.xml

[html] view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:orientation="horizontal" >  
  6.   
  7.     <ImageView   
  8.         android:layout_width="120dp"  
  9.         android:layout_height="120dp"  
  10.         android:id="@+id/imageView"  
  11.         />  
  12.   
  13.     <TextView   
  14.         android:layout_width="match_parent"  
  15.         android:layout_height="wrap_content"  
  16.         android:textSize="18sp"  
  17.         android:textColor="#FFFFFF"  
  18.         android:id="@+id/textView"          
  19.         />  
  20. </LinearLayout>  

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>
0 0
原创粉丝点击