android学习笔记---使用AsyncTask实现异步处理,内部使用线程加Handler

本文介绍了Android中使用AsyncTask进行异步处理的原理和优势,避免主线程阻塞导致的ANR错误。AsyncTask内部利用线程池和Handler实现高效的任务执行,同时提供了onPreExecute、doInBackground、onPostExecute等方法方便UI更新。通过实例展示了如何创建和使用AsyncTask加载数据,并强调了使用过程中的注意事项和权限配置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用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只能被执行一次,否则多次调用时将会出现异常;

创建Android应用:Project Name:DataAsyncLoad,Android2.2,Application Name:数据异步加载,Packagename:cn.itcast.asyncload,CreateActivity:MainActivity。

1. 清单文件中添加相应的权限

/DataAsyncLoad/AndroidManifest.xml

<?xml version="1.0"encoding="utf-8"?>

<manifestxmlns:android="http://schemas.android.com/apk/res/android"

   package="cn.itcast.asyncload"

   android:versionCode="1"

   android:versionName="1.0" >

   <uses-sdk android:minSdkVersion="8" />

   <application

       android:icon="@drawable/ic_launcher"

        android:label="@string/app_name">

        <activity

           android:label="@string/app_name"

           android:name=".MainActivity" >

            <intent-filter >

                <actionandroid:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER"/>

            </intent-filter>

        </activity>

   </application>

        <!--访问internet权限-->

<uses-permissionandroid:name="android.permission.INTERNET"/>

<!-- 在SDCard中创建与删除文件权限-->

<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>

<!-- 往SDCard写入数据权限-->

<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

       

</manifest>

2. 界面

/DataAsyncLoad/res/layout/main.xml

<?xml version="1.0"encoding="utf-8"?>

<LinearLayoutxmlns: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>

/DataAsyncLoad/res/layout/listview_item.xml

<?xml version="1.0"encoding="utf-8"?>

<LinearLayoutxmlns: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>

3. 实现

/DataAsyncLoad/src/cn/itcast/asyncload/MainActivity.java

package cn.itcast.asyncload;

import java.io.File;

import java.util.List;

importcn.itcast.adapter.ContactAdapter;

import cn.itcast.domain.Contact;

importcn.itcast.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 extendsActivity {

    ListViewlistView;

    Filecache;

   

    Handlerhandler = new Handler(){

        publicvoid 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 = newFile(Environment.getExternalStorageDirectory(), "cache");

        if(!cache.exists()) cache.mkdirs();

       

        //在线程中完成数据加载

        new Thread(new Runnable() {        

            publicvoid run() {

                try{

                    List<Contact>data = ContactService.getContacts();

                    handler.sendMessage(handler.obtainMessage(22,data));

                }catch (Exception e) {

                    e.printStackTrace();

                }

            }

        }).start();      

   }

    @Override

    protectedvoid onDestroy() {

        for(Filefile : cache.listFiles()){

            file.delete();

        }

        cache.delete();

        super.onDestroy();

    }

  

}

4. 自定义适配器

/DataAsyncLoad/src/cn/itcast/adapter/ContactAdapter.java

package cn.itcast.adapter;

import java.io.File;

import java.util.List;

import cn.itcast.asyncload.R;

import cn.itcast.domain.Contact;

importcn.itcast.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 extendsBaseAdapter {

    privateList<Contact> data;

    privateint listviewItem;

    privateFile cache;

    LayoutInflaterlayoutInflater;

   

    publicContactAdapter(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);

    }

    /**

    * 得到数据的总数

    */

    publicint getCount() {

        returndata.size();

    }

    /**

    * 根据数据索引得到集合所对应的数据

    */

    publicObject getItem(int position) {

        returndata.get(position);

    }

   

    publiclong getItemId(int position) {

        returnposition;

    }

    //每显示一个条目就调用一次该方法

    //显示第二页时会使用第一页创建的缓存

    publicView getView(intposition, View convertView, ViewGroup parent) {

        ImageViewimageView = null;

        TextViewtextView = 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(newDataWrapper(imageView, textView));

        }else{

            DataWrapperdataWrapper = (DataWrapper) convertView.getTag();

            imageView= dataWrapper.imageView;

            textView= dataWrapper.textView;   

        }

        Contactcontact = data.get(position);

        textView.setText(contact.name);

       asyncImageLoad(imageView,contact.image);//异步加载图片

        returnconvertView;

    }

   private void asyncImageLoad(ImageView imageView, String path) {

        AsyncImageTask asyncImageTask = newAsyncImageTask(imageView);

        asyncImageTask.execute(path);

       

    }

  

   private final class AsyncImageTaskextends AsyncTask<String,Integer, Uri>{

       private ImageView imageView;

        publicAsyncImageTask(ImageView imageView) {

            this.imageView= imageView;

        }

        protectedUri doInBackground(String...params) {//子线程中执行的

            try{

              returnContactService.getImage(params[0], cache);

            }catch (Exception e) {

                e.printStackTrace();

            }

            returnnull;

        }

        protectedvoid onPostExecute(Uri result) {//运行在主线程

            if(result!=null&& imageView!= null)

                imageView.setImageURI(result);

        }  

   }

    /*//不使用这种子线程的方式是因为,每显示一个条目就调用一次getView,就会创建一个线程

    privatevoid asyncImageLoad(finalImageView imageView, final String path) {

        finalHandler handler = new Handler(){

            publicvoid handleMessage(Message msg) {//运行在主线程中

                Uriuri = (Uri)msg.obj;

                if(uri!=null&& imageView!= null)

                    imageView.setImageURI(uri);

            }

        };

       

        Runnablerunnable = new Runnable() {           

            publicvoid run() {

                try{

                    Uriuri = ContactService.getImage(path, cache);

                    handler.sendMessage(handler.obtainMessage(10,uri));

                }catch (Exception e) {

                    e.printStackTrace();

                }

            }

        };

        newThread(runnable).start();

    }

*/

    privatefinal class DataWrapper{

        publicImageView imageView;

        publicTextView textView;

        publicDataWrapper(ImageView imageView, TextView textView) {

            this.imageView= imageView;

            this.textView= textView;

        }

    }

}

5. JavaBean

/DataAsyncLoad/src/cn/itcast/domain/Contact.java

package cn.itcast.domain;

public class Contact {

    publicint id;

    publicString name;

    publicString image;

    publicContact(int id, String name, String image) {

        this.id= id;

        this.name= name;

        this.image= image;

    }

    publicContact(){}

}

6. 从网络中获取数据的业务Bean

/DataAsyncLoad/src/cn/itcast/service/ContactService.java

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;

importorg.xmlpull.v1.XmlPullParser;

import android.net.Uri;

import android.util.Xml;

import cn.itcast.domain.Contact;

import cn.itcast.utils.MD5;

public class ContactService {

    /**

    * 获取联系人

    * @return

    */

    publicstatic List<Contact> getContacts() throws Exception{

        Stringpath = "http://192.168.10.100:8080/web/list.xml";

        HttpURLConnectionconn = (HttpURLConnection) new URL(path).openConnection();

        conn.setConnectTimeout(5000);

        conn.setRequestMethod("GET");

        if(conn.getResponseCode()== 200){

            returnparseXML(conn.getInputStream());

        }

        returnnull;

    }

    privatestatic List<Contact> parseXML(InputStream xml) throws Exception{

        List<Contact>contacts = new ArrayList<Contact>();

        Contactcontact = null;

        XmlPullParserpullParser = Xml.newPullParser();

        pullParser.setInput(xml,"UTF-8");

        intevent = pullParser.getEventType();

        while(event!= XmlPullParser.END_DOCUMENT){

            switch(event) {

            caseXmlPullParser.START_TAG:

                if("contact".equals(pullParser.getName())){

                    contact= new Contact();

                    contact.id= new Integer(pullParser.getAttributeValue(0));

                }elseif("name".equals(pullParser.getName())){

                    contact.name= pullParser.nextText();

                }elseif("image".equals(pullParser.getName())){

                    contact.image =pullParser.getAttributeValue(0);

                }

                break;

            caseXmlPullParser.END_TAG:

                if("contact".equals(pullParser.getName())){

                    contacts.add(contact);

                    contact= null;

                }

                break;

            }

            event= pullParser.next();

        }

        returncontacts;

    }

    /**

    * 获取网络图片,如果图片存在于缓存中,就返回该图片,否则从网络中加载该图片并缓存起来

    * @param path 图片路径

    * @return

    */

   publicstatic Uri getImage(Stringpath, File cacheDir) throws Exception{// path -> MD5 ->32字符串.jpg

        FilelocalFile = new File(cacheDir, MD5.getMD5(path)+path.substring(path.lastIndexOf(".")));

        if(localFile.exists()){

            returnUri.fromFile(localFile);

        }else{

            HttpURLConnectionconn = (HttpURLConnection) new URL(path).openConnection();

            conn.setConnectTimeout(5000);

            conn.setRequestMethod("GET");

            if(conn.getResponseCode()== 200){

                FileOutputStreamoutStream = new FileOutputStream(localFile);

                InputStreaminputStream = conn.getInputStream();

                byte[]buffer = new byte[1024];

                intlen = 0;

                while((len = inputStream.read(buffer)) != -1){

                    outStream.write(buffer,0, len);

                }

                inputStream.close();

                outStream.close();

                returnUri.fromFile(localFile);

            }

        }

        returnnull;

    }

}

7. MD5

/DataAsyncLoad/src/cn/itcast/utils/MD5.java

package cn.itcast.utils;

import java.security.MessageDigest;

importjava.security.NoSuchAlgorithmException;

public class MD5 {

    publicstatic String getMD5(String content) {

        try{

            MessageDigestdigest = MessageDigest.getInstance("MD5");

            digest.update(content.getBytes());

            returngetHashString(digest);

           

        }catch (NoSuchAlgorithmException e) {

            e.printStackTrace();

        }

        returnnull;

    }

   

   private static String getHashString(MessageDigest digest) {

        StringBuilder builder = newStringBuilder();

        for (byte b : digest.digest()) {

           builder.append(Integer.toHexString((b >> 4) & 0xf));

           builder.append(Integer.toHexString(b & 0xf));

        }

        return builder.toString();

   }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值