虽然Google的诸多服务被某某机构所封,但是仍然阻挡不了我们开发者们释放那狂热的难以抗拒的Google情怀,为此,开发者们翻山越野,寻找各种手段也要找到你!Android是Google推出的,中国那么多Android开发者,而Android官网却难以访问,此问题是否会影响国内Android程序猿的生产力?吐槽到此,转入正题,以下为一篇来自国外的关于Android Handler、Looper的文章,半译半不译的文章如下(这不是对作者不尊重,只是为了更好地表达原文的中心思想,换了国人习惯的表达方式;因为生搬硬套过来的总觉得语句不通):

Android系统,正受到广大开发者的青睐,可以说,无处不Android(不夸张(⊙o⊙)哦);开发者们喜欢Android这个平台,可能有很多理由,例如:Android开源,社区很庞大,相关资源很多;但是,我想,Android的那丰富的framework也是广大开发者们喜欢的一个理由之一,而我喜欢Android API的原因之一就是它包含了非常丰富实用的小组件,而且,有很多的组件不只是适用于Android平台,例如:Java SE平台(当然,我得承认,在Java SE平台上开发中,我忽略了它们),在浩瀚的API中, 我选中了两个重要的类:Looper and Handler,简短地介绍一把;这两个类太让我们开发者受益了,使用它们,我们能干很多非常酷的事情。

基本原理

介绍之前,先熟悉一下基本原理:Android使用这两个类实现了一个并发模型,我称这个模型为——管道线程(Pipeline Thread)(注意:这个名字只是我取的,貌似wiki上,你是收不到的,但是你可以帮忙传播一下,传着传着,大家都这么叫了,(^__^) ),这个模型的工作细节如下:
1、管道线程维护着一个任务队列,这个队列是线程安全的
2、其他的线程会安全地将任务放进管道线程所维护的任务队列
3、管道线程不停地一个接一个地从这个队列取出任务并处理,如果,这个队列中没有任何任务,它将会阻塞直到队列中有任务
4、任务队列也可以叫消息队列,这个随便你
这种设计模型有一些非常有价值的特性,并且被广泛使用在很多平台上的Framework和应用程序中;我想很多熟悉Win32消息机制开发者对这种模型可能很熟悉;因为Google在设计Anroid的消息处理机制时,确实借鉴了win32消息处理机制;随后,我会实现一个Demo:基与管道线程模型,使用Handler和Looper,模拟一个后台下载队列,并且在UI中显示它的状态;在文章的最后,你能获得完整的源码包,不过,我觉得这篇文章的最大价值不在于最后的源码包,而在于深层的原理。

管道线程模型使用场景

在诸多UI framework中,到处有着管道线程模型的身影,例如:Swing(想想事件分发线程?)、SWT、Adobe Flex、Android;这种模型被用于处理一些UI事件(click、mouse movement、屏幕旋转等等),这种模型允许你去改变一个Button的文字说明,而不必担心用户同时点击这个Button。
另一方面,这种模型强制你不要在UI Thread中做一些耗时性的操作——如果在UI Thread中下载一个网络文件,我想每一个开发者都将会知道发生什么;在我们随后的Demo中,我将在一个独立的管道线程中执行耗时性的任务,这样就保证了UI Thread的自由运作。
其他的管道线程模型的应用:
1、执行发往远程服务器的请求(通常情况,你需要连续地执行请求)
2、上传图片到HTTP服务
3、缩放或者处理图片
4、下载文件(或者其他什么),与我的Demo所做内容一样
我想,很多朋友心里都会有一个疑问,为什么要使用管道线程模型,直接使用一个单独的线程不就好了嘛,但是,有经验地程序员稍微想想就会明白,管道线程的好处:它很好地控制了后端job的负荷和时序性问题。而且,我们也可以使用多个管道线程——我们可以称之管道线程池,这样,我们就能同时执行多个任务,并且都能很好地控制负载。
在我们的Demo中,我使用了一个管道线程, 并且每次只允许一个下载任务,多个下载任务将会被有序调度。

Looping and Handling

Looper:它因其作用而得名,它实现了一个Loop(循环)——获取下一个任务,并执行它,再获取下一个任务,并执行它,如此往复;Looper将一个普通的线程变成了管道线程
Handler:它的名字没啥好说的,可能是某些人无法想到更好的名字,只能用它了;它的作用是,让我们将任务从其他线程发往管道线程
下面是一段代码放入Thread’run方法的代码,作用如下:将这个Thread变为管道线程,并创建一个Handler,允许其他的线程把任务分配给这个管道线程

@Overridepublic void run() {  try {    // preparing a looper on current thread        // the current thread is being detected implicitly    Looper.prepare();    // now, the handler will automatically bind to the    // Looper that is attached to the current thread    // You don't need to specify the Looper explicitly    handler = new Handler();    // After the following line the thread will start    // running the message loop and will not normally    // exit the loop unless a problem happens or you    // quit() the looper (see below)    Looper.loop();  } catch (Throwable t) {    Log.e(TAG, "halted due to an error", t);  }}

上述功能之后,其它的线程中将需要得到Handler对象的引用handler,并通过Handler类的方法,例如:postMessage(),发送消息(注:Handler有很多有趣的API,你可以去玩玩哦)。
下面一段代码将显示,其它的线程如何调度一个任务在管道线程中执行:

handler.post(new Runnable() {  @Override  public void run() {          // this will be done in the Pipeline Thread        }});

在我们的案例中,当用户点击Button时(这个在UI Thread中被处理),我们将使用“习语”在管道线程中调度并执行下载任务;当下载线程通知Activity下载任务已经完成时,Activity将会使用绑定在UI Thread中的Handler,这样就能保证仅仅在UI Thread中刷新UI。
随便说一句,UI Thread将会隐式地拥有一个Looper,因次你能直接在Activity的onCreate方法中创建一个Handler:

@Overridepublic void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.main);    // Create the Handler. It will implicitly bind to the Looper    // that is internally created for this thread (since it is the UI thread)    handler = new Handler();}

Demo实现细节剖析

如果你已经理解了Looper和Handler的核心思想了,我想,剩下的就是一些细节了。在我的Demo中,我主要创建了以下几个类:
1、DownloadTask:模拟了一个下载任务——我没有真实地去请求网络,不想浪费你手机的一丝流量,这样的话,也环保嘛。
2、DownloadThread:下载线程,提供一个方法,将DownloadTask放入队列,也提供了一个停止的方法
3、DownloadThreadListener:下载线程监听接口,在DownloadQueueActivity实现,当一个下载任务结束时,通过它通知UI Thread刷新UI,改变进度条
4、DownloadQueueActivity:主要的Activity,创建下载线程DownloadThread
注意:在我们的Demo中,当刷新UI中的进度条时,我们使用了一个单独的Handler,此Handler被创建在Activity中,因为我们要保证刷新UI总是UI Thread中,核心代码如下:

// note! this might be called from another thread@Overridepublic void handleDownloadThreadUpdate() {  // we want to modify the progress bar so we need to do it from the UI thread  // how can we make sure the code runs in the UI thread? use the handler!  handler.post(new Runnable() {    @Override    public void run() {      // update the UI etc.    }  });}

当然,使用DownloadThread中的handler也是可以的。想要了解更具体的,你需要去看附录Demo的完整源码和注释

总结

Loopers and Handlers,它们真得是很酷的两个类,能帮我们干很多漂亮的事情,如果,你想掀开他们那神秘的面纱,你可以去研究一下它们的源码(透露一下:其实核心就是个死循环)。

附件:完整源码包
原文地址:http://mindtherobot.com/blog/159/android-guts-intro-to-loopers-and-handlers/

更多相关文章

  1. Android(安卓)线程优先级设置方法
  2. 有关Android线程的学习
  3. Android(安卓)oom pthread_create (1040KB stack)分析及解决
  4. Android中使用Handler机制更新UI的两种方法
  5. Android(安卓)Handler解析和相关问题
  6. android字体闪烁动画(线程)
  7. Android消息处理机制4——Looper
  8. Android之SurfaceView学习
  9. 多线程实现更新android进度条。

随机推荐

  1. Android热点、WiFi、蓝牙等功能开启和关
  2. 【Android UI】ViewFlipper实现广告轮播
  3. android 打开另外一个apk并且传值过去
  4. Activity之间的通信
  5. 指纹识别分析之enroll流程
  6. android点击空白处隐藏键盘(亲测)
  7. Android搜索关键字变色
  8. 使用PhoneGap调用Camera (android)
  9. 使用googleMap 需要获取的apikey方法
  10. android倒计时广告进度条