打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Android中的Handler和AsyncTask的区别

问题的由来

最近老看见有人问Android中的Thread与AsyncTask的区别,因此研究了一下,总结如下。
第一,如果真心想弄清楚这两个的具体用法,最好的方法是把Message、MessageQueue、Looper、Handler、HandlerThread和AsyncTask这六个类的源代码全部看懂。
第二,如果觉得困难,那么就来看看我的这篇总结文章吧。

Handler类,可以理解为消息/任务处理者,Handler类是为了与其他几个类一起完成android的消息循环处理过程,是必不可少的一个类。它主要有两个用途:一是为了在将来某个时间点处理一个消息或者执行一个任务;二是将一个任务放入队列,以便它可以在另外的线程中执行。

AsyncTask类,可以理解为异步任务执行者;这个类的设计目的很明确,就是为了“执行一个较为耗时的异步任务(最多几秒钟),然后更新界面”。这种需求本可以使用Handler和Thread来实现,但由于编码较为复杂,因此Android提供了AsyncTask类。

几个规则

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

  1. 只能在UI线程中访问界面;
  2. UI线程被阻塞(大概5秒钟)后会导致ANR(Application Not Responding)错误。

因此我们要使用Handler来创建消息循环,或者使用AsyncTask来创建异步任务来进行操作。

Handler类的使用场景

消息循环三兄弟Handler、Looper和HandlerThread

Handler用来和Looper、HandlerThread一起建立一个具有消息循环的子线程。如果这三个类中有一个你不理解,那么你三个都不会理解,也不会理解Android的消息循环与处理机制。

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

一个具有完整消息循环的线程必然包括Looper、Handler和HandlerThread对象(或者你自己用Thread类来写一个线程),其中Looper对象内部还包含一个MessageQueue对象,我们这样来建立一个消息循环子线程。

   Looper anotherLooper ;   AnotherHandler anotherHandler;   HandlerThread handlerThread;   class AnotherHandler extends Handler {        public AnotherHandler(Looper looper) {            super(looper);        }        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            if (msg.what == 1234) {            Toast.makeText(MainActivity.this, String.format("Another Handler : ProcessId=%d,ThreadId=%d",getProcId(),getThreadId()), Toast.LENGTH_LONG).show();            Log.i(TAG,"message in Another Handler");            }        }    }       handlerThread = new HandlerThread("handlerThread",Process.THREAD_PRIORITY_BACKGROUND);       handlerThread.start();       anotherLooper = handlerThread.getLooper();       anotherHandler = new AnotherHandler(anotherLooper);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

记住,此处HandlerThread类不是为了运行一段自定义的代码来完成某个任务,而是为了让把消息循环运行起来,即运行Looper.loop()方法。

记住几个原则:
HandlerThread中创建了Looper对象,可以使用getLooper方法来得到这个Looper对象;
使用该Looper对象作为参数来创建Handler,才能使得此Handler能够处理消息;如果Handler对象创建时不带有对象,那么Handler会自动获取当前线程关联的Looper对象。因此若Handler是在主线程(即UI线程)中创建的,则Handler就会处理UI线程中的消息队列;如果Handler是在其他线程(此线程未创建Looper对象)中创建的,则此Handler不能处理消息。

因此,若我们不使用HandlerThread,而是直接使用Thread类,则代码如下:

class LooperThread extends Thread {         public Handler mHandler;         public void run() {             Looper.prepare();             mHandler = new Handler() {                 public void handleMessage(Message msg) {                     // process incoming messages here                 }             };             Looper.loop();         }     }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

我们会发现上面的代码例子中不能得到那个mHandler,因此收发消息时没有Handler对象可以引用,若对多线程的并发很熟悉的人可以扩展上面的代码,安全的取得该Handler对象,否则还是直接使用HandlerThread为好。

其实消息循环是五兄弟,还要加上消息(Message类)和消息队列(MessageQueue类),不过由于Message较为简单,而MessageQueue又被隐藏得很好,几乎不会被普通用户见到,因此就省略不介绍了,可以自己去看相关文档。

在主线程中使用Handler

好了,相信很多不熟悉的人看上面的消息循环三/五兄弟已经看晕了,会问“为什么我用了好久的Handler,却根本就没有见过Looper和HandlerThread呢?”
其实,那是因为绝大部分时间,你只在主线程(也就是UI线程)中使用Handler,此时Handler会默认使用主线程的Looper和Thread。可以这样理解,普通的Android应用一旦运行起来,就会创建主线程和一个主Looper,它们默默的处理着界面消息,这时你new了一个Handler并重载了它的handMessage方法,你的这个Handler对象就加入到消息的处理中来了。

具体的用法,请看我的一篇blog:Android中的消息处理实例与分析
http://blog.csdn.net/logicteamleader/article/details/46591499

在子线程使用Handler

在子线程中使用Handler则比主线程复杂,因此此时就必须使用Looper和Thread/HandlerThread类了,例子仍可以参考上一篇blog。

AsycnTask怎么来的?

好了,终于说到AsycnTask了。前面已经说过,它是一个辅助类,就是为了将Handler、Thread等封装为一个异步执行框架,供Android Coder可以方便的使用。其主要目的是为了“在其他线程中执行一个耗时操作,并随时报告执行进度给UI线程,执行完成后将结果报告给UI线程”。

AsyncTask使用方法

AsyncTask的使用方法其实Android developer中已经说得非常清楚了,我自认不能比他说得更好,因此择重点翻译一次:
AsyncTask使用时必须作为基类被扩展,子类至少重载一个方法doInBackground,另一个方法onPostExecute也经常被重载,代码例子如下:

   private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {       protected Long doInBackground(URL... urls) {           int count = urls.length;           long totalSize = 0;           for (int i = 0; i < count; i++) {               totalSize += Downloader.downloadFile(urls[i]);               publishProgress((int) ((i / (float) count) * 100));               // Escape early if cancel() is called               if (isCancelled()) break;           }           return totalSize;       }       protected void onProgressUpdate(Integer... progress) {           setProgressPercent(progress[0]);       }       protected void onPostExecute(Long result) {           showDialog("Downloaded " + result + " bytes");       }   }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

AsyncTask含有三个泛型参数:
Params, 异步任务执行所需的参数类型;
Progress, 异步任务执行进度的类型;
Result, 异步任务执行结果的类型。
这三个参数不必全部使用,不使用的参数置为Void即可,例如:

 private class MyTask extends AsyncTask<Void, Void, Void> { ... }
  • 1
  • 1

AsyncTask的四个重要方法:
当一个异步任务被执行时,要经历四步:
onPreExecute(),在UI线程中执行,它会在异步任务开始前执行,一般用来设置任务参数;
doInBackground, 最重要的方法,在子线程中执行(事实上,只有它在子线程中执行,其他方法都在UI线程中执行)。当onPreExecute结束后,本方法立刻执行,它用来进行后台的耗时计算,异步任务的参数会被传给它,执行完成的结果会被送给第四步;执行途中,它还可以调用publishProgress 方法来通知UI线程当前执行的进度;
onProgressUpdate, 当publishProgress 被调用后,它在UI线程中执行,刷新任务进度,一般用来刷新进度条等UI部件;
onPostExecute, 当后台的异步任务完成后,它会在UI线程中被调用,并获取异步任务执行完成的结果。

小结

通过上面的分析,我们可以看到,其实Handler和AsyncTask的关系不太大,可以说不是同一个层面上的东西。只不过,它们有着一些共同的目的,就是都可以用来异步执行一些代码,避免阻塞UI线程。另外,AsyncTask实际上是使用Handler和线程池技术来实现的。
要想真正的了解它们之间的异同,还是那句话:RTFSC – Read The Fucking Source Code。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Android 多线程编程的总结
关于AsyncTask与Handler
android AsyncTask介绍
Android异步处理
深入了解Android中的AsyncTask
Android开发资料
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服