android 多线程Thread,Runnable,Handler,AsyncTask等之间的关系

android 的多线程实际上就是java的多线程。android的UI线程又称为主线程。

我们创建的Service、Activity以及Broadcast均是一个主线程处理,这里我们可以理解为UI线程。但是在操作一些耗时操作时,比如I/O读写的大文件读写,数据库操作以及网络下载需要很长时间,为了不阻塞用户界面,出现ANR的响应提示窗口,这个时候我们可以考虑使用Thread线程来解决。

Thread 和 Runnable

关于这两者的关系,很多人会说,在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口;Thread类是在java.lang包中定义的。一个类只要继承了Thread类同时覆写了本类中的run()方法就可以实现多线程操作了,但是一个类只能继承一个父类,这是此方法的局限。所以,通常会实现Runnable接口方式。

Thread才是一个线程,而Runnable可以理解为一个任务。这个任务只是一个接口。具体的任务执行是在 run()方法执行。

Thread thread = new Thread(Runnable);

 那么就是把一个Runnable任务放到线程里面。当调用thread.start() 的时候,系统新开一个线程去执行,这个runnable任务是在多线程执行的。是在新开的线程执行的。

但是thread.run() ,这样子实际上只是在UI线程执行了Runnable 并没有实现多线程。系统也没有新开一个线程。

如果直接 new Runnable().run();那么实际上是直接在UI线程执行了这个任务没有进行一个多线程的操作。

总结:runnable()只是一个任务的抽象,并不是多线程。Thread.start()。才是新开一个多线程。并且在新开的线程执行Thread你们的run()方法。

但是,在实现时,当使用 runnable 接口时,不能直接创建所需类的对象并运行它;必须从 Thread 类的一个实例内部运行它。

如:class test implements Runnable 

     Thread thread = new Thread(new test());  

Handler

是android 的多线程通信机制的产物,在Android中不允许Activity新启动的线程访问该Activity里的UI组件,这样会导致新启动的线程无法改变UI组件的属性值。但实际开发中,很多地方需要在工作线程中改变UI组件的属性值,比如下载网络图片、动画等等。

Handler,它直接继承自Object,一个Handler允许发送和处理Message或者Runnable对象,并且会关联到主线程的MessageQueue中。每个Handler具有一个单独的线程,并且关联到一个消息队列的线程,就是说一个Handler有一个固有的消息队列。当实例化一个Handler的时候,它就承载在一个线程和消息队列的线程,这个Handler可以把Message或Runnable压入到消息队列,并且从消息队列中取出Message或Runnable,进而操作它们。

Handler可以把一个Message对象或者Runnable对象压入到消息队列中,进而在UI线程中获取Message或者执行Runnable对象,所以Handler把压入消息队列有两大体系,Post和sendMessage:

对于Handler的Post方式来说,它会传递一个Runnable对象到消息队列中,在这个Runnable对象中,重写run()方法。一般在这个run()方法中写入需要在UI线程上的操作。hanlder实际上是不涉及多线程的。

post(Runnable)  让当前线程执行Runnable任务。如果是在主线程调用,那么就是在UI线程执行Runnable。实际上没有多线程执行runnable。
postAtTime(Runnable,long)  也是让当前线程在 时间点long 执行Runnble
postDelayed(Runnable long) 让当前线程延时 long 后执行Runnable。

这3个方法实际上可以把handler看成是一个任务调度器,而不是一个多线程相关的。



Handler如果使用sendMessage的方式把消息入队到消息队列中,需要传递一个Message对象,而在Handler中,需要重写handleMessage()方法,用于获取工作线程传递过来的消息,此方法运行在UI线程上。

Message自带的有如下几个属性:

  • int arg1:参数一,用于传递不复杂的数据,复杂数据使用setData()传递。
  • int arg2:参数二,用于传递不复杂的数据,复杂数据使用setData()传递。
  • Object obj:传递一个任意的对象。
  • int what:定义的消息码,一般用于设定消息的标志。
对于Message对象,一般并不推荐直接使用它的构造方法得到,而是建议通过使用Message.obtain()这个静态的方法或者Handler.obtainMessage()获取。Message.obtain()会从消息池中获取一个Message对象,如果消息池中是空的,才会使用构造方法实例化一个新Message,这样有利于消息资源的利用。并不需要担心消息池中的消息过多,它是有上限的,上限为10个。Handler.obtainMessage()具有多个重载方法,如果查看源码,会发现其实Handler.obtainMessage()在内部也是调用的Message.obtain()。

sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long) 发出消息的方法

handleMessage(Message msg)处理消息 这才是android 的hanlder的多线程通信用到的,看下图


可以看到3个线程共用一个消息队列Message Queue,一个消息循环器Looper(作用不断循环读取消息队列的消息)。

另外2个线程通过hanlder的sendMessage等方法发送Message,message中可以包含数据。或者是一些action的标记值。

主线程的hanlder通过handleMessage把包含数据等信息的消息取出来。这个过程中其他线程的数据通过message+hanlder传递到主线程实现的多线程通信。

可以在一个线程的run方法中调用handler对象的 postMessage或sendMessage方法来实现,Android程序内部维护着一个消息队列,会轮询处理这些消息。

Message.obtain()方法具有多个重载方法,大致可以分为为两类,一类是无需传递Handler对象,对于这类的方法,当填充好消息后,需要调用Handler.sendMessage()方法来发送消息到消息队列中。第二类需要传递一个Handler对象,这类方法可以直接使用Message.sendToTarget()方法发送消息到消息队列中,这是因为在Message对象中有一个私有的Handler类型的属性Target,当时obtain方法传递进一个Handler对象的时候,会给Target属性赋值,当调用sendToTarget()方法的时候,实际在它内部还是调用的Target.sendMessage()方法。

AsyncTask

可以开启一个多线程执行任务,并且多线程的数据传递也是有这个类自己完成。

实际上AsyncTask 是由 thread + handler的封装实现。所以AsyncTask 跟Thread+handler实现没有本质的差别。

AsyncTask的代码更少,使用比Thread+handler简单。

主要有    onPreExecute() ; 是指在执行多线程任务之前的一个初始化执行。在UI线程调用

      doInBackground(Params... params);这个方法是AsyncTask新启动的线程实现的。在新线程调用
    onPostExecute(Result result) ;这个是doInBackground()方法执行完成后,才调用的方法。

result 就是doInBackground()的结果,就是用Hanlder的方式传递的数据。这个方法在UI线程调用

    protected void onProgressUpdate(Progress... values);处理中间数据。doInBackGround()方法中,即在新开的线程中调用publishProgress方法,那么hanlder就把publishProgress的值传递到UI线程中。

并且把值交给onProgressUpdate方法处理。所以onProgressUpdate是在UI线程调用的。

本文转自 http://blog.csdn.net/liu_qiqi/article/details/37902205


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值