Android多线程通信机制

在Android中我们把UI线程外的线程成为工作线程。我们不能再主线程中做耗时操作,如网络廉连接,IO操作。
因此我们可以把耗时操作放到另一个线程中去做,操作完成后再通知主线程做相应响应。这就需要掌握线程间通信方式。
Androiod提供了两种线程间通信方式:一种是AsyncTask机制,另一种是Handler机制。

1.线程间通信方式之AsyncTask机制:
AsyncTask异步任务,也就是说在线程运行的时候,也可以在后台执行一些异步的操作。
AsyncTask允许进行后台操作,并在不显示使用工作线程和Handler机制情况下,将结果返回给UI线程。AsyncTask只适用于短时间的操作。

1.1AsyncTask使用
AsyncTask只能通过继承使用:


 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;
     }
    //更新后台任务的完成进度,可随时向UI线程反馈执行进度,方法是在UI线程中执行的
     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }
    //任务的最终结果,这个方法是在UI线程中执行的,
     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }

AsyncTask的几个参数:
Params:要执行的任务的参数类型
Progress:后台执行任务的进度
Result:后台执行任务的最终结果

当一个AsyncTask任务执行时,它会经历四个步骤:
onPreExecute():
任务执行前调用,用来做一些UI初始化工作,在UI线程中执行
doInBackground():
后台执行任务,工作线程中执行
onProgressUpdate():
更新正在后台执行任务的进度,在主线程中工作,可用来通知用户任务现在的完成进度,在调用这个方法前,需要在第2个步骤里调用 publishProgress(Progress…)将进度传递给这个方法;
onPostExecute():
在后台任务完成后,会将结果返回给这个方法,在UI线程中调用,可以更新UI;

在使用AsyncTask的时候,需要注意的地方:

AsyncTask类必须在UI线程中加载,这在在Android Jelly_Bean版本后这些都是自动完成的;

AsyncTask类必须在UI线程中实例化;

不要手动去调用onPreExecute(),doInBackground(Params…),publishProgress(Progress…),onPostExecute(Result)方法,这些方法都会由系统自动去调用。

execute(Params…)方法必须在UI线程中调用,如在UI线程中执行这个语句:new DownloadFilesTask().execute(url1, url2, url3);我们不需要做其他的工作,这个下载任务就会自动在后台执行了,并且AsynacTask任务只能执行一次;

2.线程间通信方式之Handler机制:*
Handler,发送和处理Message对象和Runnable对象;
Looper,用于从MessageQueue中取出消息(Message)对象,并发送给Handler处理;
MessageQueue:消息队列,用于存放Handler发布的消息;
Message:消息的类型,里面包含几个实例对象;

what,用户定义的int型消息代码,用来描述消息;
obj,随消息发送的用户指定对象;
target,处理消息的Handler;
一个Handler仅与一个Looper相关联,一个Message也仅与一个目标Handler对象相关联,一个Looper对象拥有一个MessageQueue,但多个不同的Handler对象也可以与同一个对象相关联。也就是说,Handler可以共享一个MessageQueue,从而达到消息共享的目的。者也是Android通过Handler机制实现多线程间通信的原理。

上面说到Handler对象仅与一个Looper相关联,那么这个关联是什么时候实现的呢?答案是:Handler对象创建的时候。UI线程在创建的时候就拥有一个Handler对象和一个Looper对象。(工作线程需要自己调用Looper.prepare()来创建一个Looper对象),然后任何在主线程中创建的Handler对象都会默认与主线程的Looper对象相关联。(Handler对象创建的时候,会与这个线程的Looper对象相关联)。进而我们就可以把在UI主线程中创建的Handler传递给工作线程,那么在工作线程中用这个Handler对象处理的消息就是就是在UI主线程的MessageQueue中处理的。

了解了使用Handler机制来实现Android线程间异步通信的原理,下面我们再来详细了解下这四个核心类;

2.1Handler
Handler,继承自Object,用来发送或处理Message或Runnable对象,Handler在创建时,会与当前所在线程的Looper对象相关联(如果当前线程的Looper对象为空或不存在,咋会报异常,此时需要在线程中主动调用Looper.prepare()来创建Looper对象)。使用Handler的作用就是:在后面的过程中发送和处理Message对象和让其他的线程完成某一动作(如在工作线程中通过Handler发送一个Message对象,在UI线程在更新UI,然后UI线程就会在MessageQueue中得到这个Message(取出Message对象是由其相关联的Looper对象完成的),并作出相应的响应)。

Handler用post来完成发送Runnable对象工作,用sendMessage来发送消息;
post允许把一个Runnable对象发送到消息队列中,它的方法有:
post(Runnable),postDelayed(Runnable,long),postAtTime(Runnable,long);
handler用sendMessage把Message对象发送到消息队列,它的方法有:
sendEmptyMessage(int),sendMessage(Message),sendMessageDelayed(Message,long),sendMessageAtTime(Message,long);

如果Handler是通过post体系将Runnable对象发送到MessageQueue队列中,则这个Runnable对象的run()方法是运行在Handler对象创建时所在线程;
如果Handler是通过sendMessage体系将Message发送到MessageQueue中,则需要重写handleMessage()方法来获取工作线程传递过来的Message对象,handleMessage()方法是工作在Handler对象建立时所在的线程的。

2.2Mssage
Message用来定义一个
包含任意数据的消息对象,这个对象可以被发送给 Handler处理。我们最好通过Message.obtain()或Handler.obtainMessage()来获取一个Message对象(通过这两个方法得到的对象是从对象回收池中得到,也就是说是复用已经处理完的Message对象,而不是重新生成一个新对象),如果通过Message的构造方法得到一个Message对象,则这个对象是重新生成的。

Message{
int arg1;//如果我们只需要存储一些简单的Integer数据,则可通过设置这个属性来传递
int agr2;//使用同arg1
Object obj; //设置需要发送给接收方的对象,这个对象需要实现序列化接口
int what; //描述这个消息的标识;
//设置与这个消息对应的任意数据,这个数据是用Bundle封装的;
void setData(Bundle data);
Bundle getData(); 得到与这个消息对应的数据信息;
//省略了方法和可选的属性
......

2.3MessageQueue
MessageQueue保存由Looper调度的消息列表,消息通过与Looper相关联的Handler对象添加进MessageQueue。
2.4Looper
Looper为线程运行一个消息的循环队列,主要就是完成Message与Handler交互功能。需要注意的是线程默认并不会给我们提供一个一个Looper实例来管理消息队列,我们需要在线程中主动调用Looper.prepare()方法来实例化一个Looper对象,用于管理消息队列;Looper对象会不断的去判断MessageQueue是否为空,如果不空,则将Message取出给相应的Handler处理;如果为空,Looper就会进入阻塞状态,直到有新的消息进入MessageQueue。

其实,说白了,Android中通过Handler机制来异步处理多线程间的通信就是多个线程间共享一个MessageQueue,工作线程将Message发送到MessageQueue,然后UI线程或其他线程在MessageQueue中取出,进行相应处理。

补充说明:
子线程更新UI的四种方法:
1.handlr.post(Runnable r)
2.handler.handlerMessage(Message msg)
3.runOnUiThread(Runnable r)
4.View.post(Runnable r)

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值