服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Android - Android Handler之消息循环的深入解析

Android Handler之消息循环的深入解析

2021-01-17 17:15Android开发网 Android

本篇文章是对Handler消息循环进行了详细的分析介绍,需要的朋友参考下

handler是用于操作线程内部的消息队列的类。这有点绕,没关系,我们慢慢的来讲。前面looper一篇讲到了looper是用于给线程创建消息队列用的,也就是说looper可以让消息队列(messagequeue)附属在线程之内,并让消息队列循环起来,接收并处理消息。但,我们并不直接的操作消息队列,而是用handler来操作消息队列,给消息队列发送消息,和从消息队列中取出消息并处理。这就是handler的职责。
handler,looper和messagequeue是属于一个线程内部的数据,但是它提供给外部线程访问的接口,handler就是公开给外部线程,与线程通讯的接口。换句话说,这三个东西都是用来线程间通讯用的(itc--inter thread communication),与进行间通讯(ipc--inter process communication)的消息队列msgque的核心思想是一致的。messagequeue是相对较底层的,较少直接使用,looper和handler就是专门用来操作底层messagequeue的。
还有一个重要的数据结构是通讯的基本元素,就是消息对象(message),message从来不单独使用,它都是跟随handler来使用的。具体方法可以参考文档,但需要注意的是同一个消息对象不能发送二次,否则会有androidruntimeexception: { what=1000 when=-15ms obj=.. } this message is already in use."。每次发送消息前都要通过message.obtain()来获取新的对象,或者,对于不需要传送额外数据的直接发送空消息就好handler.sendemptymessage(int)。另外也需要注意消息对象是不能手动回收的,也就是说你不能调用message.recycle()来释放一个消息对象,因为当该对象被从队列中取出处理完毕后,messagequeue内部会自动的去做recycle()。这个理解起来也很容易,因为发送一个消息到消息队列后,消息什么时候会被处理,对于应用程序来讲是不知道的,只有messagequeue才会知道,所以只能由messagequeue来做回收释放的动作。
因为handler是用于操作一个线程内部的消息队列的,所以handler必须依附于一个线程,而且只能是一个线程。换句话说,你必须在一个线程内创建handler,同时指定handler的回调handlermessage(message msg)。
handler主要有二个用途,一个是用于线程内部消息循环; 另外一个就是用于线程间通讯。
handler的基本用法可以参考文档,说的还是比较清楚的。
用于线程内部消息循环
主要是用作在将来定时做某个动作,或者循环性,周期性的做某个动作。主要的接口就是
    handler.sendemptymessagedelayed(int msgid, long after);
    handler.sendmessagedelayed(message msg, long after);
    handler.postdelayed(runnable task, long after);
    handler.sendmessageattime(message msg, long timemillis);
    handler.sendemptymessageattime(int id, long timemiilis);
    handler.postattime(runnable task, long timemillis);

这些方法的目的都是设置一个定时器,在指定的时间后,或者在指定的时间向handler所在的messagequeue发送消息。这样就非常方便应用程序实现定时操作,或者循环时序操作(处理消息时再延时发送消息,以达成循环时序)。

这个使用起来并不难,但需要注意一点的是,线程内部消息循环并不是并发处理,也就是所有的消息都是在handler所属的线程内处理的,所以虽然你用post(runnable r),发给messagequeue一个runnable,但这并不会创建新的线程来执行,处理此消息时仅是调用r.run()。(想要另起线程执行,必须把runnable放到一个thread中)。
实例
这里用一个实例来展示主线程通过handler与后台线程进行通信,并且主线程用handler来实现循环时序。
Android Handler之消息循环的深入解析Android Handler之消息循环的深入解析
播放一个视频,线程用于创建和初始化mediaplayer,初始化好后会通过主线程的handler告诉主线程,然后主线程可以播放视频,在播放过程中通过sendmessagedelayed()来实现播放进度的不断更新:

复制代码 代码如下:


public class handlersimpledemo extends activity {
    protected static final string tag = "handlersimpledemo";
    private static final int media_player_ready = 0;
    private static final int refresh_progress = 1;

    private button mstart;
    private button mstop;
    private surfaceholder msurfaceholder;
    private progressbar mprogressbar;
    private surfaceview mdisplay;
    private mediaplayer mmediaplayer;

    private handler mmainhandler = new handler() {
 @override
 public void handlemessage(message msg) {
     switch (msg.what) {
     case media_player_ready:
  mprogressbar.setmax(mmediaplayer.getduration());
  mmediaplayer.setoncompletionlistener(new mediaplayer.oncompletionlistener() {
      public void oncompletion(mediaplayer mp) {
   mprogressbar.setprogress(mmediaplayer.getduration());
   mmainhandler.removemessages(refresh_progress);
      }
  });
  mstart.setenabled(true);
  mstop.setenabled(true);
  break;
     case refresh_progress:
  int cp = mmediaplayer.getcurrentposition();
  mprogressbar.setprogress(cp);
  int delay = 1000 - (cp % 1000);
  mmainhandler.sendemptymessagedelayed(refresh_progress, delay);
  break;
     default:
  break;
     }
 }
    };

    @suppresswarnings("deprecation")
    @override
    protected void oncreate(bundle savedinstancestate) {
 super.oncreate(savedinstancestate);
 setcontentview(r.layout.handler_simple_demo);
 mstart = (button) findviewbyid(r.id.handler_simple_start);
 mstart.setonclicklistener(new view.onclicklistener() {
     public void onclick(view v) {
  mmediaplayer.start();
  mmainhandler.sendemptymessage(refresh_progress);
     }
 });
 mstart.setenabled(false);
 mstop = (button) findviewbyid(r.id.handler_simple_stop);
 mstop.setonclicklistener(new view.onclicklistener() {
     public void onclick(view v) {
  mmainhandler.removemessages(refresh_progress);
  mmediaplayer.pause();
     }
 });
 mstop.setenabled(false);
 mprogressbar = (progressbar) findviewbyid(r.id.handler_simple_progress);
 mdisplay = (surfaceview) findviewbyid(r.id.handler_simple_display);
 msurfaceholder = mdisplay.getholder();
 msurfaceholder.setfixedsize(mdisplay.getwidth(), mdisplay.getheight());
 // do not believe the document, settype is necessary, otherwise, video won't play correctly
 msurfaceholder.settype(surfaceholder.surface_type_push_buffers);

 new thread(new runnable() {
     public void run() {
  try {
      mmediaplayer = mediaplayer.create(getapplication(), r.raw.flug);
      mmediaplayer.setdisplay(msurfaceholder);
      mmainhandler.sendemptymessage(media_player_ready);
  } catch (illegalargumentexception e) {
      log.e(tag, "caught exception e", e);
  } catch (securityexception e) {
      log.e(tag, "caught exception e", e);
  } catch (illegalstateexception e) {
      log.e(tag, "caught exception e", e);
  }
     }
 }).start();
    }
    @override
    protected void ondestroy() {
 super.ondestroy();
 mmainhandler.removemessages(refresh_progress);
 if (mmediaplayer != null) {
     mmediaplayer.release();
 }
    }
}

延伸 · 阅读

精彩推荐
  • AndroidAndroid CardView+ViewPager实现ViewPager翻页动画的方法

    Android CardView+ViewPager实现ViewPager翻页动画的方法

    本篇文章主要介绍了Android CardView+ViewPager实现ViewPager翻页动画的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    Abby代黎明9592022-03-02
  • AndroidAndroid实现固定屏幕显示的方法

    Android实现固定屏幕显示的方法

    这篇文章主要介绍了Android实现固定屏幕显示的方法,实例分析了Android屏幕固定显示所涉及的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...

    鉴客6182021-03-27
  • AndroidAndroid程序设计之AIDL实例详解

    Android程序设计之AIDL实例详解

    这篇文章主要介绍了Android程序设计的AIDL,以一个完整实例的形式较为详细的讲述了AIDL的原理及实现方法,需要的朋友可以参考下...

    Android开发网4622021-03-09
  • AndroidAndroid界面效果UI开发资料汇总(附资料包)

    Android界面效果UI开发资料汇总(附资料包)

    android ui界面设计,友好的界面会提高用户体验度;同时也增强了android ui界面设计的难度,本文提供了一些常用开发资料(有下载哦)感兴趣的朋友可以了解下...

    Android开发网4652021-01-03
  • Android汇总Android视频录制中常见问题

    汇总Android视频录制中常见问题

    这篇文章主要汇总了Android视频录制中常见问题,帮助大家更好地解决Android视频录制中常见的问题,需要的朋友可以参考下...

    yh_thu5192021-04-28
  • AndroidAndroid实现Service获取当前位置(GPS+基站)的方法

    Android实现Service获取当前位置(GPS+基站)的方法

    这篇文章主要介绍了Android实现Service获取当前位置(GPS+基站)的方法,较为详细的分析了Service基于GPS位置的技巧,具有一定参考借鉴价值,需要的朋友可以参考下...

    Ruthless8332021-03-31
  • AndroidAndroid中AsyncTask详细介绍

    Android中AsyncTask详细介绍

    这篇文章主要介绍了Android中AsyncTask详细介绍,AsyncTask是一个很常用的API,尤其异步处理数据并将数据应用到视图的操作场合,需要的朋友可以参考下...

    Android开发网7432021-03-11
  • AndroidAndroid编程解析XML方法详解(SAX,DOM与PULL)

    Android编程解析XML方法详解(SAX,DOM与PULL)

    这篇文章主要介绍了Android编程解析XML方法,结合实例形式详细分析了Android解析XML文件的常用方法与相关实现技巧,需要的朋友可以参考下...

    liuhe68810042021-05-03