• Handler初探


      允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://52android.blog.51cto.com/2554429/470542

        Android中有着和J2SE同样优秀的多线程支持,可以把那些耗时较多的操作放在新线程中操作。但是当新线程中有涉及到操作UI的操作时,就会对主线程产生危险,因此,Android提供了Handler作为主线程和子线程的纽带。同时,Handler对象初始化后,就默认与对它初始化的进程的消息队列绑定,因此可以利用Handler所包含的消息队列,制定一些操作的顺序。

       根据SDK文档的说明:“A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue.”由此可以清楚的知道,可以把消息和Runnble对象发送到与Handler对象所关联的消息队列中去。

        

         下面,就Handler的以上两点作用,分别进行讨论。

        1. 传递Message。用于接受子线程发送的数据, 并用此数据配合主线程更新UI。

        在Android中,对于UI的操作通常需要放在主线程中进行操作。如果在子线程中有关于UI的操作,那么就需要把数据消息作为一个Message对象发送到消息队列中,然后,有Handler中的handlerMessge方法处理传过来的数据信息,并操作UI。当然,Handler对象是在主线程中初始化的,以为它需要绑定在主线程的消息队列中。

        类sendMessage(Message msg)方法实现发送消息的操作。 在初始化Handler对象时重写的handleMessage方法来接收Messgae并进行相关操作。

      

     
     

    1. //Handler处理子线程消息代码示例:  
    2.  
    3. public class Activity01 extends Activity  
    4. {  
    5.     //声明ProgressBar对象  
    6.     private ProgressBar m_ProgressBar;  
    7.     private ProgressBar m_ProgressBar2;  
    8.     private Button mButton01;  
    9.     protected static final int GUI_STOP_NOTIFIER = 0x108;  
    10.     protected static final int GUI_THREADING_NOTIFIER = 0x109;  
    11.     public int intCounter=0;  
    12.     /** Called when the activity is first created. */ 
    13.     @Override 
    14.     public void onCreate(Bundle savedInstanceState)  
    15.     {  
    16.         super.onCreate(savedInstanceState);  
    17.         //设置窗口模式,,因为需要显示进度条在标题栏  
    18.         requestWindowFeature(Window.FEATURE_PROGRESS);  
    19.         setProgressBarVisibility(true);  
    20.         setContentView(R.layout.main);  
    21.           
    22.         //取得ProgressBar  
    23.         m_ProgressBar = (ProgressBar) findViewById(R.id.ProgressBar01);  
    24.         m_ProgressBar2= (ProgressBar) findViewById(R.id.ProgressBar02);  
    25.         mButton01 = (Button)findViewById(R.id.Button01);   
    26.           
    27.         m_ProgressBar.setIndeterminate(false);  
    28.         m_ProgressBar2.setIndeterminate(false);  
    29.           
    30.         //当按钮按下时开始执行,  
    31.         mButton01.setOnClickListener(new Button.OnClickListener()  
    32.         {  
    33.           @Override 
    34.           public void onClick(View v)  
    35.           {  
    36.             // TODO Auto-generated method stub  
    37.                 
    38.               //设置ProgressBar为可见状态  
    39.               m_ProgressBar.setVisibility(View.VISIBLE);  
    40.               m_ProgressBar2.setVisibility(View.VISIBLE);  
    41.               //设置ProgressBar的最大值  
    42.               m_ProgressBar.setMax(100);  
    43.               //设置ProgressBar当前值  
    44.               m_ProgressBar.setProgress(0);  
    45.               m_ProgressBar2.setProgress(0);  
    46.  
    47.               //通过线程来改变ProgressBar的值  
    48.   new Thread(new Runnable() {  
    49.      public void run()  
    50.         {  
    51.      for (int i = 0; i < 10; i++)  
    52.         {  
    53.            try 
    54.            {  
    55.                  intCounter = (i + 1) * 20;  
    56.                  Thread.sleep(1000);  
    57.  
    58.             if (i == 4)  
    59.             {  
    60.             Message m = new Message();  
    61.  
    62.              m.what = Activity01.GUI_STOP_NOTIFIER;  
    63.             Activity01.this.myMessageHandler.sendMessage(m);
    64. //将message发送到消息队列  
    65.               break;  
    66.              }  
    67.             else 
    68.            {  
    69.            Message m = new Message();  
    70.            m.what = Activity01.GUI_THREADING_NOTIFIER;  
    71.            Activity01.this.myMessageHandler.sendMessage(m);  
    72. //将message发送到消息队列  
    73.                                 }  
    74.                             }  
    75.                             catch (Exception e)  
    76.                             {  
    77.                                 e.printStackTrace();  
    78.                             }  
    79.                         }  
    80.                     }  
    81.                 }).start();  
    82.             }  
    83.         });  
    84.     }  
    85.  
    86. //通过匿名类复写Handler类中的handleMessage方法,用于接收传递到消息队列中的Message,并进行UI操作。
    87.       Handler myMessageHandler = new Handler()  
    88.       {  
    89.         // @Override   
    90.           public void handleMessage(Message msg)  
    91.           {  
    92.               switch (msg.what)  
    93.               {  
    94.               //ProgressBar已经是对大值  
    95.               case Activity01.GUI_STOP_NOTIFIER:  
    96.                   m_ProgressBar.setVisibility(View.GONE);  
    97.                   m_ProgressBar2.setVisibility(View.GONE);  
    98.                   Thread.currentThread().interrupt();  
    99.                   break;  
    100.               case Activity01.GUI_THREADING_NOTIFIER:  
    101.                   if (!Thread.currentThread().isInterrupted())  
    102.                   {  
    103.                       // 改变ProgressBar的当前值  
    104.                       m_ProgressBar.setProgress(intCounter);  
    105.                       m_ProgressBar2.setProgress(intCounter);  
    106.                         
    107.                       // 设置标题栏中前景的一个进度条进度值  
    108.                       setProgress(intCounter*100);  
    109.                       // 设置标题栏中后面的一个进度条进度值  
    110.                       setSecondaryProgress(intCounter*100);//  
    111.                   }  
    112.                   break;  
    113.               }  
    114.               super.handleMessage(msg);  
    115.          }  
    116.       };  
    117. }  

        以上的例子中,子线程只是对进度条的参数进行了变更,并将结果以message形式发送到消息队列中去,子线程的内部并未进行UI操作,而是在重写的Handler的handlerMessage方法中操作了UI界面。

        2. 传递Runnable对象。用于通过Handler绑定的消息队列,安排不同操作的执行顺序。

        Handler对象在进行初始化的时候,会默认的自动绑定消息队列。利用类post方法,可以将Runnable对象发送到消息队列中,按照队列的机制按顺序执行不同的Runnable对象中的run方法。

       

    1. public class HandlerActivity extends Activity {  
    2.     /** Called when the activity is first created. */ 
    3.     //声明两个按钮控件  
    4.     private Button startButton = null;  
    5.     private Button endButton = null;  
    6.     @Override 
    7.     public void onCreate(Bundle savedInstanceState) {  
    8.         super.onCreate(savedInstanceState);  
    9.         setContentView(R.layout.main);  
    10.         //根据控件的ID得到代表控件的对象,并未这两个按钮设置相应的监听器  
    11.         startButton = (Button)findViewById(R.id.startButton);  
    12.         startButton.setOnClickListener(new StartButtonListener());  
    13.         endButton = (Button)findViewById(R.id.endButton);  
    14.         endButton.setOnClickListener(new EndButtonListener());  
    15.           
    16.     }  
    17.     class StartButtonListener implements OnClickListener{  
    18.  
    19.         @Override 
    20.         public void onClick(View v) {  
    21.             //调用Handler的post方法,将要执行的线程对象添加到队列当中  
    22.             handler.post(updateThread);  
    23.         }  
    24.           
    25.     }  
    26.       
    27.     class EndButtonListener implements OnClickListener{  
    28.  
    29.         @Override 
    30.         public void onClick(View v) {  
    31.             handler.removeCallbacks(updateThread);  
    32.         }  
    33.           
    34.     }  
    35.     //创建一个Handler对象  
    36.     Handler handler  = new Handler();  
    37.     //将要执行的操作写在线程对象的run方法当中  
    38.     Runnable updateThread =  new Runnable(){  
    39.  
    40.         @Override 
    41.         public void run() {  
    42.             System.out.println("UpdateThread");  
    43.             //在run方法内部,执行postDelayed或者是post方法  
    44.             handler.postDelayed(updateThread, 3000);  
    45.         }  
    46.           
    47.     };  

        程序的运行结果就是每隔3秒钟,就会在控制台打印一行UpdateTread。这是因为实现了Runnable接口的updateThread对象进入了空的消息队列即被立即执行run方法,而在run方法的内部,又在3000ms之后将其再次发送进入消息队列中。

       3. Handler和多线程

        post方法虽然发送的是一个实现了Runnable接口的类对象,但是它并非创建了一个新线程,而是执行了该对象中的run方法。也就是说,整个run中的操作和主线程处于同一个线程。

        这样对于那些简单的操作,似乎并不会影响。但是对于耗时较长的操作,当它被加入到消息队列中之后执行会占用很长的时间,以至于处于同一线程的其他操作无法继续执行,就会出现“假死”。为了解决这个问题,就需要使得handler绑定到一个新开启线程的消息队列上,在这个处于另外线程的上的消息队列中处理传过来的Runnable对象和消息。SDK文档中也提供了相关说明:

         When a process is created for your application, its main thread is dedicated to running a message queue that takes care of managing the top-level application objects (activities, broadcast receivers, etc) and any windows they create. You can create your own threads, and communicate back with the main application thread through a Handler. This is done by calling the same post or sendMessage methods as before, but from your new thread. The given Runnable or Message will than be scheduled in the Handler's message queue and processed when appropriate.

         具体操作方法如下:

     
     

    1. public class HandlerTest2 extends Activity {  
    2.  
    3.     @Override 
    4.     protected void onCreate(Bundle savedInstanceState) {  
    5.         // TODO Auto-generated method stub  
    6.     super.onCreate(savedInstanceState);  
    7.     setContentView(R.layout.main);  
    8.     //打印了当前线程的ID  
    9.     System.out.println("Activity-->" + Thread.currentThread().getId());  
    10.     //生成一个HandlerThread对象  
    11.     HandlerThread handlerThread = new HandlerThread("handler_thread");  
    12.     //在使用HandlerThread的getLooper()方法之前,必须先调用该类的start(),同时开启一个新线程;  
    13.     handlerThread.start();
    14. //将由HandlerThread获取的Looper传递给Handler对象,即由处于另外线程的Looper代替handler初始化时默认绑定的消息队列来处理消息。  
    15.     MyHandler myHandler = new MyHandler(handlerThread.getLooper());  
    16.     Message msg = myHandler.obtainMessage();  
    17.     //将msg发送到目标对象,所谓的目标对象,就是生成该msg对象的handler对象  
    18.     Bundle b = new Bundle();  
    19.     b.putInt("age"20);  
    20.     b.putString("name""Jhon");  
    21.     msg.setData(b);  
    22.     msg.sendToTarget();  //将msg发送到myHandler
    23.     }  
    24.       
    25. //定义类
    26.     class MyHandler extends Handler{  
    27.     public MyHandler(){  
    28.               
    29.     }  
    30.     public MyHandler(Looper looper){  
    31.         super(looper);  
    32.     }  
    33.     @Override 
    34.     public void handleMessage(Message msg) {  
    35.         Bundle b = msg.getData();  
    36.         int age = b.getInt("age");  
    37.         String name = b.getString("name");  
    38.         System.out.println("age is " + age + ", name is" + name);  
    39.         System.out.println("Handler--->" + Thread.currentThread().getId());  
    40.         System.out.println("handlerMessage");  
    41.         }  
    42.     }  
    43. }  

        这样,当使用sendMessage方法传递消息或者使用post方法传递Runnable对象时,就会把它们传递到与handler对象绑定的处于另外一个线程的消息队列中,它们将在另外的消息队列中被处理。而主线程还会在发送操作完成时候继续进行,不会影响当前的操作。

        这里需要注意,这里用到的多线程并非由Runnable对象开启的,而是ThreadHandler对象开启的。Runnable对象只是作为一个封装了操作的对象被传递,并未产生新线程。

    本文出自 “我的Android开发志” 博客,请务必保留此出处http://52android.blog.51cto.com/2554429/470542

  • 相关阅读:
    MongoDB查询修改操作语句命令大全
    SpringBoot读取war包jar包Resource资源文件解决办法
    linux lsof命令详解
    taskset
    POI导出excel,本地测试没问题,linux测试无法导出
    js中文乱码
    处理Account locked due to 217 failed logins的问题
    普通用户无法su到root用户
    gp数据库停止
    eclipse导入maven工程missing artifact(实际是存在的)错误解决
  • 原文地址:https://www.cnblogs.com/xiaoxiaoboke/p/2088143.html
Copyright © 2020-2023  润新知