zoukankan      html  css  js  c++  java
  • Android中Handler Thread及Runnable之间的关系

    在多线程编程这块,我们经常要使用Handler,Thread和Runnable这三个类,那么他们之间的关系你是否弄清楚了呢?

        首先说明Android的CPU分配的最小单元是线程,Handler一般是在某个线程里创建的,因而Handler和Thread就是相互绑定的,一一对应。

        而Runnable是一个接口,Thread是Runnable的子类。所以说,他俩都算一个进程。

        HandlerThread顾名思义就是可以处理消息循环的线程,他是一个拥有Looper的线程,可以处理消息循环。

        与其说Handler和一个线程绑定,不如说Handler是和Looper一一对应的。

        最后需要说明的是,在UI线程(主线程)中:

        mHandler=new Handler();

        mHandler.post(new Runnable(){

        void run(){

           //执行代码...

     

         }

        });

        这个线程其实是在UI线程之内运行的,并没有新建线程。

     

        常见的新建线程的方法是:

        Thread thread = new Thread();

        thread.start();

     

        HandlerThread thread = new HandlerThread("string");

        thread.start();

     

     

     

     

     

     

    AndroidHandler的使用方法——构建定时器 收藏 

        在这篇文章中,我将继上一篇,讲解用Handler来构建最简单的周期性触发的定时器,您可以加以修改,构建更为复杂的定时器。

     

       ◆ 在代码中定义一个整形常量,代表消息的ID。此处不妨对其取名为TIMERID。   

     

       ◆创建自己的Handler,在该HandlerHandlerMessage处理函数中。在消息处理函数中,我们首先发送消息TIMERID,并指定其延迟的时间,单位为毫秒。然后可以调用相应的事务处理函数。需要注意的是,如果事件处理函数花费的时间过长,则下次消息到来时,会导致不能及时处理。

     

       ◆创建startTimer函数,在该函数中触发定时器,实际上就是发送一个TIMERID消息,来第一次触发消息。

     

       ◆创建stopTimer函数,在该函数中停止定时器,实际上就是把TIMERID的消息从消息队列中删除即可。

     

        下面让我们来以代码作为说明。

     

     1 package com.android.mytimer; 
     2 
     3  
     4 
     5 import android.os.Handler; 
     6 
     7 import android.os.Message; 
     8 
     9  
    10 
    11 public class MyTimer extends Handler 
    12 
    13 { 
    14 
    15         private static int TIMERID = 0; //静态变量,保证ID唯一。当ID超过整形最大值时,应该把它恢复为0 
    16 
    17         private final int mInterval; 
    18 
    19         public interface CallBack{ 
    20 
    21             void timerCallBack(); 
    22 
    23         }
    24 
    25  
    26 
    27  
    28 
    29         private CallBack mCallBack;
    30 
    31  
    32 
    33         public MyTimer(int interval, CallBack callback) 
    34 
    35         { 
    36 
    37             mInterval = interval; 
    38 
    39             mCallBack = callback; 
    40 
    41             TIMERID++; 
    42 
    43         }
    44 
    45  
    46 
    47  
    48 
    49         @Override 
    50 
    51         public void handleMessage(Message msg) { 
    52 
    53             // TODO Auto-generated method stub 
    54 
    55             super.handleMessage(msg); 
    56 
    57             if( msg.what == TIMERID) 
    58 
    59             { 
    60 
    61                 Message message = obtainMessage(TIMERID); 
    62 
    63                 this.sendMessageDelayed(message, mInterval); 
    64 
    65                 //for speed up, NO NULL Pointer exception check 
    66 
    67                 mCallBack.timerCallBack(); 
    68 
    69             } 
    70 
    71         } 
    72 
    73  
    74 
    75         public void startTimer() 
    76 
    77         { 
    78 
    79             Message msg = this.obtainMessage(TIMERID); 
    80 
    81             this.sendMessage(msg); 
    82 
    83         }
    84 
    85  
    86 
    87  
    88 
    89         public void stopTimer() 
    90 
    91         { 
    92 
    93             this.removeMessages(TIMERID); 
    94 
    95         } 
    96 
    97 }

     

    其中接口CallBack是一个回调函数,使用这个定时器的应用必须实现该接口,并且在构造函数当中传入该类。如下

     

        

    public class TestTimer implement MyTImer.CallBack 
    
        { 
    
            MyTimer mTimer; 
    
            public TestTimer() 
    
            { 
    
                mTimer = new MyTImer(10, this); 
    
                mTimer.start(); 
    
            } 
    
            void timerCallBack(); 
    
            { 
    
                Log.i("TestTimer", "this is the timerCallBack"); 
    
            } 
    
        }
    
    

     

     

     

    本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yangpeng98/archive/2010/06/19/5680043.aspx

     

     

     

     

     

    一> Handler的定义:

              主要接受子线程发送的数据, 并用此数据配合主线程更新UI.

              解释: 当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件,进行事件分发, 比如说, 你要是点击一个 Button ,Android会分发事件到Button上,来响应你的操作。  如果此时需要一个耗时的操作,例如: 联网读取数据,    或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,,如果你放在主线程中的话,界面会出现假死现象, 如果5秒钟还没有完成的话,,会收到Android系统的一个错误提示  "强制关闭".  这个时候我们需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,,Android主线程是线程不安全的,也就是说,更新UI只能在主线程中更新,子线程中操作是危险的. 这个时候,Handler就出现了.,来解决这个复杂的问题 ,    由于Handler运行在主线程中(UI线程中),  它与子线程可以通过Message对象来传递数据, 这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象,(里面包含数据)  , 把这些消息放入主线程队列中,配合主线程进行更新UI。(文/springhi-2009)

    <二> Handler一些特点

            handler可以分发Message对象和Runnable对象到主线程中, 每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程),
            它有两个作用: (1):  安排消息或Runnable 在某个主线程中某个地方执行, (2)安排一个动作在不同的线程中执行
          
            Handler中分发消息的一些方法
            post(Runnable)
            postAtTime(Runnable,long)
            postDelayed(Runnable long)
            sendEmptyMessage(int)
            sendMessage(Message)
            sendMessageAtTime(Message,long)
            sendMessageDelayed(Message,long)

            以上post类方法允许你排列一个Runnable对象到主线程队列中,
            sendMessage类方法, 允许你安排一个带数据的Message对象到队列中,等待更新.

    <三> Handler实例

          (1) 子类需要继承Hendler类,并重写handleMessage(Message msg) 方法, 用于接受线程数据

          以下为一个实例,它实现的功能为 : 通过线程修改界面Button的内容

      1 public class MyHandlerActivity extends Activity {
      2   
      3 
      4     Button button;
      5   
      6 
      7      MyHandler myHandler;
      8   
      9 
     10  
     11   
     12 
     13     protected void onCreate(Bundle savedInstanceState) {
     14   
     15 
     16         super.onCreate(savedInstanceState);
     17   
     18 
     19          setContentView(R.layout.handlertest);
     20   
     21 
     22  
     23   
     24 
     25          button = (Button) findViewById(R.id.button);
     26   
     27 
     28          myHandler = new MyHandler();
     29   
     30 
     31          // 当创建一个新的Handler实例时, 它会绑定到当前线程和消息的队列中,开始分发数据
     32   
     33 
     34          // Handler有两个作用, (1) : 定时执行Message和Runnalbe 对象
     35   
     36 
     37          // (2): 让一个动作,在不同的线程中执行.
     38   
     39 
     40   
     41 
     42          // 它安排消息,用以下方法
     43   
     44 
     45          // post(Runnable)
     46   
     47 
     48          // postAtTime(Runnable,long)
     49   
     50 
     51          // postDelayed(Runnable,long)
     52   
     53 
     54          // sendEmptyMessage(int)
     55   
     56 
     57          // sendMessage(Message);
     58   
     59 
     60          // sendMessageAtTime(Message,long)
     61   
     62 
     63          // sendMessageDelayed(Message,long)
     64   
     65 
     66         
     67   
     68 
     69          // 以上方法以 post开头的允许你处理Runnable对象
     70   
     71 
     72          //sendMessage()允许你处理Message对象(Message里可以包含数据,)
     73   
     74 
     75  
     76   
     77 
     78          MyThread m = new MyThread();
     79   
     80 
     81          new Thread(m).start();
     82   
     83 
     84      }
     85   
     86 
     87  
     88   
     89 
     90      /**
     91   
     92 
     93       * 接受消息,处理消息 ,此Handler会与当前主线程一块运行
     94   
     95 
     96       * */
     97   
     98 
     99  
    100   
    101 
    102      class MyHandler extends Handler {
    103   
    104 
    105          public MyHandler() {
    106   
    107 
    108          }
    109   
    110   
    111 
    112          public MyHandler(Looper L) {
    113   
    114 
    115              super(L);
    116   
    117 
    118          }
    119   
    120 
    121  
    122   
    123 
    124          // 子类必须重写此方法,接受数据
    125   
    126 
    127         @Override
    128   
    129 
    130         public void handleMessage(Message msg) {
    131   
    132 
    133              // TODO Auto-generated method stub
    134   
    135 
    136             Log.d("MyHandler", "handleMessage......");
    137   
    138 
    139              super.handleMessage(msg);
    140   
    141 
    142              // 此处可以更新UI
    143   
    144 
    145             Bundle b = msg.getData();
    146   
    147 
    148              String color = b.getString("color");
    149   
    150 
    151              MyHandlerActivity.this.button.append(color);
    152   
    153 
    154  
    155   
    156 
    157     } 
    158 
    159    }
    160   
    161 
    162  
    163   
    164 
    165      class MyThread implements Runnable {
    166   
    167 
    168          public void run() {
    169   
    170 
    171  
    172   
    173 
    174              try {
    175   
    176 
    177                  Thread.sleep(10000);
    178   
    179 
    180              } catch (InterruptedException e) {
    181   
    182 
    183                 // TODO Auto-generated catch block
    184   
    185 
    186                  e.printStackTrace();
    187   
    188 
    189              }
    190   
    191 
    192  
    193   
    194 
    195             Log.d("thread.......", "mThread........");
    196   
    197 
    198              Message msg = new Message();
    199   
    200 
    201             Bundle b = new Bundle();// 存放数据
    202   
    203 
    204              b.putString("color", "我的");
    205   
    206 
    207              msg.setData(b);
    208   
    209 
    210  
    211   
    212 
    213              MyHandlerActivity.this.myHandler.sendMessage(msg); // 向Handler发送消息,更新UI
    214   
    215 
    216  
    217   
    218 
    219          }
    220   
    221 
    222      }
    223   
    224 
    225   
    226 
    227  } 

     

  • 相关阅读:
    LeetCode: Reverse Linked List
    DataBase: MySQL在.NET中的应用
    DataBase: LeetCode
    DirectShow+VS2010+Win7配置说明
    MathType应用:批量改变公式格式
    $LaTeX$笔记:首字下沉
    Latex学习笔记-序
    反思--技术博客的写作应该是怎样的?
    用Latex写学术论文:作者(Author)&摘要(Abstract)
    用Latex写学术论文: IEEE Latex模板和文档设置(documentclass)
  • 原文地址:https://www.cnblogs.com/qingblog/p/2597705.html
Copyright © 2011-2022 走看看