您的位置:首页 > 移动开发 > Android开发

android 异步方式实现数据加载

2016-09-25 11:52 429 查看
使用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

package cn.org.domain;  
  
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(){}  
}  

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

[html]
view plain
copy

package cn.itcast.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 android.net.Uri;  
import android.util.Xml;  
  
import cn.org.domain.Contact;  
import cn.org.utils.MD5;  
  
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;  
    }  
  
    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;  
    }  
  
}  

[html]
view plain
copy

package cn.org.utils;  
  
import java.security.MessageDigest;  
import java.security.NoSuchAlgorithmException;  
  
public class MD5 {  
  
    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;  
    }  
      
    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();  
    }  
}  

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

[html]
view plain
copy

package cn.org.adapter;  
  
import java.io.File;  
import java.util.List;  
  
import cn.org.asyncload.R;  
import cn.org.domain.Contact;  
import cn.org.service.ContactService;  
import android.content.Context;  
import android.net.Uri;  
import android.os.AsyncTask;  
import android.os.Handler;  
import android.os.Message;  
import android.view.LayoutInflater;  
import android.view.View;  
import android.view.ViewGroup;  
import android.widget.BaseAdapter;  
import android.widget.ImageView;  
import android.widget.TextView;  
  
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;  
    }  
  
    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 {  
                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);  
        }     
    }  
  
    private final class DataWrapper{  
        public ImageView imageView;  
        public TextView textView;  
        public DataWrapper(ImageView imageView, TextView textView) {  
            this.imageView = imageView;  
            this.textView = textView;  
        }  
    }  
}  

4.MainActivity.java

[html]
view plain
copy

package cn.org.asyncload;  
  
import java.io.File;  
import java.util.List;  
  
import cn.org.adapter.ContactAdapter;  
import cn.org.domain.Contact;  
import cn.org.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));  
        }         
    };  
      
    @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();  
    }  
      
}  

5.listview_item.xml

[html]
view plain
copy

<?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>  

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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐