zoukankan      html  css  js  c++  java
  • Handler类和Handler,Loop,MessageQueue的工作原理

    原文地址:http://blog.csdn.net/xiyangyang8/article/details/50754771


    Handler类的作用主要有两种:

    1.在新启动的线程中发送消息。

    2.在主线程(UI线程)中获取,处理消息。

    注:主线程已经封装有Loop的消息队列处理机制,无需再创建。

    Handler类包括例如以下方法用于消息发送,处理:

    1.void handleMessage(Message msg):处理消息的方法。

    2.final boolean hasMessages(int what):检查消息队列是否包括what的值。

    3.final boolean hasMessages(int what, Object object):检查消息队列是否包括what的值且object为指定对象。

    4.Message obtainMessage():获取消息。

    5.sendEmptyMessage(int what):发送空消息。

    6.final boolean sendemptyMessageDelayed(int what, long delayMillis):指定多少毫秒之后发送空消息。

    7.final boolean sendMessage(Message msg):马上发送消息。

    8.final boolean sendMessageDelayed(Message msg, long delayMillis):指定多少毫秒之后发送空消息。

     

    demo:自己主动播放动画

    以下代码实现是创建一个新线程来隔一定时间之后周期性的改动ImageView所显示的图片。实现一个动画效果。

    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. public class HandlerActivity extends Activity {  
    2.         //定义周期性显示的图片ID  
    3.         int[] imageIds = new int[]  
    4.         {  
    5.                 R.drawable.1,  
    6.                 R.drawable.2,  
    7.                 R.drawable.3,  
    8.                 R.drawable.4,  
    9.                 R.drawable.5  
    10.         };  
    11.         int currentImageId = 0;  
    12.         @Override  
    13.         public void onCreate(Bundle savedInstanceState)  
    14.         {  
    15.             super.onCreate(savedInstanceState);  
    16.             setContentView(R.layout.main_activity);  
    17.             final ImageView show = (ImageView) findViewById(R.id.main_bt);  
    18.               
    19.             final Handler myhHandler = new Handler()  
    20.             {  
    21.                 @Override  
    22.                 public void handleMessage(Message msg)  
    23.                 {  
    24.                     //假设该消息是本程序所发送的  
    25.                     if (msg.what == 0x12345) {  
    26.                         //动态的改动所显示的图片  
    27.                         show.setImageResource(imageIds[currentImageId++]%imageIds.length);  
    28.                     }  
    29.                 }  
    30.             };  
    31.             //定义一个计时器,让该计时器周期性的运行指定任务  
    32.             new Timer().schedule(new TimerTask() { //TimerTask对象的本质是启动一个新线程  
    33.                   
    34.                 @Override  
    35.                 public void run() {  
    36.                     // TODO Auto-generated method stub  
    37.                     //发送空消息  
    38.                     myhHandler.sendEmptyMessage(0x12345);  
    39.                 }  
    40.             }, 01200);  
    41.         }  
    42.     }  

    说明:当Timertask新线程发送消息时。位于主线程的handleMessage(Message msg)方法自己主动被回调。动态的改动ImagView组件的属性。效果:由新线程来周期性的改动ImageView的属性。从而实现动画效果。

     

    Handler,Looper。MessageQueue的工作原理:

    Looper:每一个线程仅仅有一个Looper,它负责管理MessageQueue,会不断的从MessageQueue中取出消息,并将消息分发给Handler处理。

    MessageQueue:由Looper负责管理。

    它採用先进先出的方式来管理Message。

    Handler:它能把消息发送给Looper管理的MessageQueue。并负责处理Looper分给它的消息。

    注:

    • 在主线程中。系统已经初始化了一个Looper对象,因此程序直接创建Handler就可以,然后就可通过Handler来发送消息,处理消息。
    • 在自己启动的子线程。必须自己创建一个Looper对象,并启动它(分别调用prepare()和loop()方法),以下解说这两个方法:
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. public static final void prepare(){  
    2.         if (sThreadLocal.get() != null) {  
    3.             throw new RuntimeException("Only one Looper may be created per thread");  
    4.         }  
    5.         sThreadLocal.set(new Looper());  
    6.     }  

    说明:prepare方法保证线程最多仅仅有一个Looper对象。

    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. public void loop(){  
    2.         for (; ;) {  
    3.             Message msg = queue.next();//获取消息队列的下一个消息。假设没有消息,将会堵塞  
    4.             if (msg == null) {//假设消息为null,表明消息队列正在退出  
    5.                 return;  
    6.             }  
    7.             Printer logging = me.mLogging;  
    8.             if (logging != null) {  
    9.                 logging.println("");  
    10.             }  
    11.             msg.target.dispatchMessage(msg);  
    12.             if (logging != null) {  
    13.                 logging.println("");  
    14.             }  
    15.             //使用final修饰该标识符。保证在分发消息的过程中线程标识符不会被改动  
    16.             final long newIdent = Binder.clearCallingIdentity();  
    17.             if (iden != newIdent) {  
    18.                 logging.println("");  
    19.             }  
    20.             msg.recycle();  
    21.         }  
    22.     }  

    说明:loop()方法使用一个死循环不断取出MessageQueue中的消息,并将取出的消息分给该消息相应的Handler进行处理。


    在非主线程中使用Handler的过程例如以下:

    • 调用Looper的prepare()方法为当前线程创建Looper对象(创建Looper对象时。它的构造器会自己主动创建与之配套的MessageQueue)。
    • 有了Looper之后,创建Handler子类的实例,重写handleMessage()方法。该方法负责处理来自于其它线程的消息。
    • 调用Looper的loop()方法启动Looper。

    Demo:使用新线程计算质数

    该实例同意用户输入一个数值上限,当用户单击“计算”button时,该应用会将该上限数值发送到新启动的线程。让该线程来计算该范围内的全部质数(之所以不直接在UI线程中计算该范围的全部质数。是由于UI线程须要响应用户动作,假设在UI线程中运行一个耗时操作,将会导致UI线程被堵塞。引起ANR异常)。

    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. /* 
    2.      * 本实例在线程中创建一个Handler对象,然后UI线程的事件处理方法通过Handler向新线程发送消息。 
    3.      */   
    4.     public class CalPrime extends Activity{  
    5.         static final String UPPER_NUM = "upper";  
    6.         EditText etNum;  
    7.         CalThread calThread;  
    8.         class CalThread extends Thread{  
    9.             public Handler mHandler;  
    10.             public void run(){  
    11.                 Looper.prepare();  
    12.                 mHandler = new Handler(){  
    13.                     @Override  
    14.                     public void handleMessage(Message msg){  
    15.                         if (msg.what == 0x123) {  
    16.                             int upper = msg.getData().getInt(UPPER_NUM);  
    17.                             List<Integer> nums = new ArrayList<Integer>();  
    18.                             //计算从2開始,到upper的全部质数  
    19.                             outer:  
    20.                                 for (int i = 2; i <= upper; i++) {  
    21.                                     //用i除以从2開始。到i的平方根的全部数  
    22.                                     for (int j = 2; j <= Math.sqrt(i); j++) {  
    23.                                         //假设能够整除。表明这个数不是质数  
    24.                                         if (i != 2 && i % j == 0) {  
    25.                                             continue outer;  
    26.                                         }  
    27.                                     }  
    28.                                     nums.add(i);  
    29.                                 }  
    30.                             //使用Toast显示统计出来的全部质数  
    31.                             Toast.makeText(CalPrime.this, nums.toString(), Toast.LENGTH_LONG).show();  
    32.                               
    33.                         }  
    34.                     }  
    35.                 };  
    36.                 Looper.loop();  
    37.             }  
    38.         }  
    39.     }  
    40.     @Override  
    41.     public void onCreate(Bundle savedInstanceState){  
    42.         super.onCreate(savedInstanceState);  
    43.         setContentView(R.layout.main_activity);  
    44.         etNum = (EditText)findViewById(R.id.etNum);  
    45.         CalThread calThread = new CalThread();  
    46.         calThread.start();//启动新线程  
    47.     }  
    48.     //为button的点击事件提供事件处理函数  
    49.     public void cal(View source){  
    50.         //创建消息  
    51.         Message msg = new Message();  
    52.         msg.what = 0x123;  
    53.         Bundle bundle = new Bundle();  
    54.         bundle.putInt(UPPER_NUM, Integer.parseInt(etNum.getText().toString()));  
    55.         msg.setData(bundle);  
    56.         //向新线程中的Handler发送消息  
    57.         calThread.mHandler.sendMessage(msg);  
    58.           
    59.     }  
  • 相关阅读:
    基础实验7-2.2 插入排序还是堆排序 (25分)
    进阶实验6-3.1 红色警报 (25分)--并查集
    基础实验3-2.2 单链表分段逆转 (25分)--单链表
    基础实验6-2.2 汉密尔顿回路 (25分)--邻接矩阵
    案例6-1.3 哥尼斯堡的“七桥问题” (25分)--dfs图连通+度判断
    基础实验8-1.1 单身狗 (25分)
    基础实验7-2.3 德才论 (25分)--排序
    基础实验7-2.4 PAT排名汇总 (25分)--结构体排序(快排)
    进阶实验4-3.4 笛卡尔树 (25分)--二叉排序树+堆排序
    基础实验4-2.7 修理牧场 (25分)-堆+哈夫曼树
  • 原文地址:https://www.cnblogs.com/llguanli/p/8467463.html
Copyright © 2011-2022 走看看