• 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.     }  
  • 相关阅读:
    「日常训练」Single-use Stones (CFR476D2D)
    「日常训练」Greedy Arkady (CFR476D2C)
    「Haskell 学习」二 类型和函数(上)
    「学习记录」《数值分析》第二章计算实习题(Python语言)
    「日常训练」Alena And The Heater (CFR466D2D)
    Dubbo 消费者
    Dubbo 暴露服务
    Rpc
    git fail to push some refs....
    Spring Cloud (6)config 客户端配置 与GitHub通信
  • 原文地址:https://www.cnblogs.com/llguanli/p/8467463.html
Copyright © 2020-2023  润新知