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:定义的消息码,一般用于设定消息的标志。
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/u012565107/article/details/22749677
handler部分摘自:http://www.cnblogs.com/plokmju/p/android_handler.html