从现实生活中理解线程消息机制

Android中主线程的说法错误的是 android 主线程handler_Android

android 有一种叫消息队列的说法,这里我们可以这样理解:假如一个隧道就是一个消息队列,那么里面的每一部汽车就是一个一个消息,这里我们先忽略掉超车等种种因素,只那么先进隧道的车将会先出,这个机制跟我们android 的消息机制是一样的。

Android 的线程消息机制

android 在设计的时候引入了 wince 的消息机制,即将每一个消息发送到队列里面,遵循先进先出原则。发送消息并不会阻塞线程,而接收线程会阻塞线程,这是因为 Android 的Handler 机制,当Handler 处理完一个 Message 对象才会接着去取下面一个消息进行处理,如下图:

Android中主线程的说法错误的是 android 主线程handler_Android_02

这里记住:Android里并没有Global的Message Queue数据结构,例如,不同APK里的对象不能透过Massage Queue来交换讯息(Message)。例如:线程A的Handler对象可以传递消息给别的线程,让别的线程B或C等能送消息来给线程A(存于A的Message Queue里)。线程A的Message Queue里的讯息,只有线程A所属的对象可以处理。

案例分析:

经典的歌词同步,这时我们不仅要听到优质的歌曲,还要可以有歌词同步,这时另开一条线程来处理歌词的同步是比较好的解决办法,你可以根据自己的定义,抓取歌曲的duration 在线程中处理歌词的前进或者后退。。。

Demo 分析:

Android中主线程的说法错误的是 android 主线程handler_Android中主线程的说法错误的是_03

下面我们来实现一个Iphone 上的一个通过按数字后,数字过多消除的按钮事件。事件的原理如下,事件要的效果是这样的,当长按消除按钮后,数字会慢慢消除,过会消除速度会增快,那么实现这个效果我们就需要自己做一个小键盘,我做的键盘效果如下:

Android中主线程的说法错误的是 android 主线程handler_移动开发_04

我们通过点击

Android中主线程的说法错误的是 android 主线程handler_Android中主线程的说法错误的是_05

来达到这个效果,使用的是android 的线程机制。实现代码如下:

private   Threadthread;
   private 
  TextViewtv_call_no;
   protected 
   
  static 
  RunnableRunablerun 
  = 
   
  null 
  ;
   private 
  Handlerhandler;
   private 
   
  int 
  textLength 
  = 
   
  0 
  ;
   private 
   
  boolean 
  isStop 
  = 
   
  true 
  ;


首先将要使用的数据类型声明在头部,将会使用到 java 的 Thread 和Android Handler 对象,首先实现Runable 对象,代码如下:


Runablerun   = 
   
  new 
  Runnable(){

@Override
   public 
   
  void 
  run(){
   // 
  TODOAuto-generatedmethodstub 
  
    
  try 
  {
   int 
  i 
  = 
   
  0 
  ;
   do 
  {
i   ++ 
  ;
Thread.sleep(i   > 
   
  15 
   
  ? 
   
  20 
  : 
  100 
  );
Messagemsg   = 
  handler.obtainMessage();
msg.arg1   = 
  i;
msg.sendToTarget();
   if 
  (i 
  == 
  textLength){
isStop   = 
   
  false 
  ;
}
}   while 
  (isStop);
}   catch 
  (Exceptione){
   // 
  TODO:handleexception 
  
   }
}
};


上面代码还可以如此写法:

Messagemsg   = 
  new 
  Message();
msg.arg1   = 
  i;
handler.sendMessage(msg);


第一种写法是message 从handler 类获取,从而可以直接向该handler 对象发送消息,第二种写法是直接调用 handler 的发送消息方法发送消息。不过不管是第一种方法好还是第二种方法好,都要在同样的handler 接收消息,否则会报异常。下面实现handler 对象,代码如下:

/**   
*启动线程
*
*   @param 
  tv
*   @param 
  text
*   @return 
  
   */ 
  
   public 
  HandlergetHandler( 
  final 
  TextViewtv, 
  final 
  Stringtext){
Handlerhand   = 
   
  new 
  Handler(){
   public 
   
  void 
  handleMessage(Messagemsg){

tv.setText(text.substring(   0 
  ,text.length() 
  - 
  msg.arg1));

   super 
  .handleMessage(msg);
};
};
   return 
  hand;

}


这里返回一个handler 对象,实际上是返回去给上面我们的handler 对象使用,这里我把它封装成一个方法,可以让它在每次接收到消息后去使用消息处理文本每次减1

设置

Android中主线程的说法错误的是 android 主线程handler_Android中主线程的说法错误的是_05

的 onTouch 事件,使其在弹出时停止递减:

/**   
*点击back删除之前的数据,跳出就停止删除
   */   
OnTouchListenerontouch   =    
  new 
  OnTouchListener(){

@Override
   public    
  boolean 
  onTouch(Viewv,MotionEventevent){
   //   TODOAuto-generatedmethodstub 
  
   
Stringtext   =   tv_call_no.getText().toString();
   if   (text.length() 
  == 
   
  0 
  ){
isStop   =    
  false 
  ;
   return    
  false 
  ;
}
   switch   (event.getAction()){
   case   MotionEvent.ACTION_DOWN:
isStop   =    
  true 
  ;
textLength   =   tv_call_no.getText().length();

handler   =   getHandler(tv_call_no,text);
thread   =    
  new 
  Thread(Runablerun);
thread.start();
   break   ;
   case   MotionEvent.ACTION_UP:
isStop   =    
  false 
  ;
   break   ;

}
   return    
  false 
  ;
}
};


小结:

  • 1、向哪个Handler 发送消息,就必须在哪个handler 里面接收;
  • 2、直接使用JAVA 的 Thread 是无法更新Android UI的,因为Android View 在设计的时线程是不完全的,不过Android 提供了几种供开发者在线程中更新UI的方法,如下:
  • Activity.runOnUiThread( Runnable )

View.post( Runnable ) View.postDelayed( Runnable, long ) Hanlder 3、直接使用hanlder .post 等方法是在当前主线程里面做操作,而不是另外新建线程,建议使用Thread 线程直接新建另外一个线程或者使用HandlerThread类也可以。 4、记住消息队列的先进先出原则。