Handler和AsyncTask的使用及优缺点比较

AsyncTaskHandler都是为了不阻塞主线程而执行异步操作的类。

正式开始讨论HandlerAsyncTask之前,有几个Android的规则要强调一次:

1.只能在UI线程中访问界面;

2.UI线程被阻塞(大概5秒钟)后会导致ANR(Application Not Responding)错误。

 

Handler:

主要接收子线程发送的数据,然后用此数据配合主线程更新UI

简单说一下Handler机制,这涉及到HandlerLooperHandlerThread

Looper轮询器:Looper中带有一个MessageQueue(消息队列),Looper负责轮询此消息队列,将Message(消息)取出后交由Handler来处理。 
HandlerThread消息循环线程:即Handler执行的线程,此线程大部分时间都在运行Looper.loop()方法,即消息轮询方法;它会通过getLooper方法返回一个Looper对象,Handler需要使用此对象作为参数创建对象。 
Handler处理者:负责接收消息、发送消息和处理消息(handleMessage方法),我们需要重载handleMessage方法来处理各种消息。

 

Handler的一些方法:

post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable,long)
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)

以上post类方法允许你排列一个Runnable对象到主线程队列中,

sendMessage类方法, 允许你安排一个带数据的Message对象到队列中,等待更新.

 

AsyncTask

AsyncTask是一个辅助类,就是为了将HandlerThread等封装为一个异步执行框架,方便调用。主要目的是为了“在其他线程中执行一个耗时操作,并随时报告执行进度给UI线程,执行完成后将结果报告给UI线程”。

它直接继承Object,为我们体用了三个泛型并重载了几个方法

三种泛型:

Params 启动任务执行的输入参数,比如HTTP请求的URL

Progress 后台任务执行的进度。

Result 后台执行任务最终返回的结果,比如String

 

当一个异步任务被执行的时候,需要经历四步:

onPreExecute():-----在UI线程中执行,它会在异步任务开始前执行,一般用来设置任务参数; 
doInBackground(): ----接收任务参数,执行异步任务,返回结果传给第四步;执行途中,它还可以调用publishProgress方法来通知UI线程当前执行的进度;  (只有它在子线程中执行,其他方法都在UI线程中执行)
onProgressUpdate(): ----当publishProgress被调用后,刷新任务进度。
onPostExecute():----当后台的异步任务完成后,它会在UI线程中被调用,并获取异步任务执行完成的结果。

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

onProgressUpdate(Progress…)  -----在UI线程中执行,刷新任务进度。
onCancelled()             ------用户调用取消时,要做的操作

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

§ Task的实例必须在UI thread中创建;

§ execute方法必须在UI thread中调用;

§ 不要手动的调用onPreExecute(), onPostExecute(Result)doInBackground(Params...), onProgressUpdate(Progress...)这几个方法;

§ task只能被执行一次,否则多次调用时将会出现异常;

 

封装一个AsyncTask进行图片加载示例:

public class NetCacheUtils {
    private static final String TAG = "NetCacheUtils";
    private ImageView imageView;
    public void getBitmapFromNet(ImageView imageView, String url) {
        //2.执行  :异步加载类对象.excute(Params... params);
        //异步下载图片
        new BitmapTask().execute(imageView, url);
    }
    /**
     * 1.自定义异步加载类
     * @Params Params:输入参数。对应的是调用自定义的AsyncTask的类中调用excute()方法中传递的参数。如果不需要传递参数,则直接设为Void即可。
     * @Params Progress:后台任务子线程执行的百分比
     * @Params Result:后台执行任务最终返回结果。和doInBackground()方法的返回值类型保持一致。
     */
    class BitmapTask extends AsyncTask<Object, Void, Bitmap> {//Params,Progress,Result
        private ImageView imageView;
        private String url;

    //这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }
        /**
         * 后台线程执行异步任务,将result告知UI线程。
         * 返回值类型和Result保持一致。参数:若无就传递Void;若有,就可用Params
         */
        @Override
        protected Bitmap doInBackground(Object... params) {
            imageView = (ImageView) params[0];
            url = (String) params[1];
            imageView.setTag(url);//给当前ImageView打标签
            //使用url下载图片
            Bitmap bitmap = download(url);
            return bitmap;
        }
        /**
         * 相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回
         * 参数:和Result保持一致
         */
        @Override
        protected void onPostExecute(Bitmap result) {
            if (result != null) {
                //给ImageView设置图片
                //由于ListView的重用机制,导致某个item有可能展示它所重用的那个item的图片, 导致图片错乱
                //解决方案:确保当前设置的图片和当前显示的imageview完全匹配
                String url = (String) imageView.getTag();//获取和当前ImageView绑定个url
                if (this.url.equals(url)) {//判断当前下载的图片的url是否和imageView的url一致, 如果一致,说明图片正确
                    imageView.setImageBitmap(result);
                    System.out.println("从网络下载图片啦!!!");
                }
            }
        }
    }
}

更多:http://blog.csdn.net/LogicTeamLeader/article/details/51165375


阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页