Handler

来源:互联网 发布:linux localdns查看 编辑:程序博客网 时间:2024/05/19 14:19
    Android中有着和J2SE同样优秀的多线程支持,可以把那些耗时较多的操作放在新线程中操作。但是当新线程中有涉及到操作UI的操作时,就会对主线程产生危险,因此,Android提供了Handler作为主线程和子线程的纽带。同时,Handler对象初始化后,就默认与对它初始化的进程的消息队列绑定,因此可以利用Handler所包含的消息队列,制定一些操作的顺序。
下面,就Handler的以上两点作用,分别进行讨论。
1. 传递Message。用于接受子线程发送的数据, 并用此数据配合主线程更新UI。   
    在Android中,对于UI的操作通常需要放在主线程中进行操作。如果在子线程中有关于UI的操作,那么就需要把数据消息作为一个Message对象发送到消息队列中,然后,有Handler中的handlerMessge方法处理传过来的数据信息,并操作UI。当然,Handler对象是在主线程中初始化的,以为它需要绑定在主线程的消息队列中。
    类sendMessage(Message msg)方法实现发送消息的操作。 在初始化Handler对象时重写的handleMessage方法来接收Messgae并进行相关操作。

//Handler处理子线程消息代码示例:   public class Activity01 extends Activity  {      //声明ProgressBar对象      private ProgressBar m_ProgressBar;      private ProgressBar m_ProgressBar2;      private Button mButton01;      protected static final int GUI_STOP_NOTIFIER = 0x108;      protected static final int GUI_THREADING_NOTIFIER = 0x109;      public int intCounter=0;      /** Called when the activity is first created. */     @Override     public void onCreate(Bundle savedInstanceState)      {          super.onCreate(savedInstanceState);          //设置窗口模式,,因为需要显示进度条在标题栏          requestWindowFeature(Window.FEATURE_PROGRESS);          setProgressBarVisibility(true);          setContentView(R.layout.main);                    //取得ProgressBar          m_ProgressBar = (ProgressBar) findViewById(R.id.ProgressBar01);          m_ProgressBar2= (ProgressBar) findViewById(R.id.ProgressBar02);          mButton01 = (Button)findViewById(R.id.Button01);                     m_ProgressBar.setIndeterminate(false);          m_ProgressBar2.setIndeterminate(false);                    //当按钮按下时开始执行,          mButton01.setOnClickListener(new Button.OnClickListener()          {            @Override           public void onClick(View v)            {              // TODO Auto-generated method stub                                //设置ProgressBar为可见状态                m_ProgressBar.setVisibility(View.VISIBLE);                m_ProgressBar2.setVisibility(View.VISIBLE);                //设置ProgressBar的最大值                m_ProgressBar.setMax(100);                //设置ProgressBar当前值                m_ProgressBar.setProgress(0);                m_ProgressBar2.setProgress(0);                 //通过线程来改变ProgressBar的值    new Thread(new Runnable() {       public void run()          {       for (int i = 0; i < 10; i++)          {             try            {                   intCounter = (i + 1) * 20;                   Thread.sleep(1000);               if (i == 4)              {              Message m = new Message();                m.what = Activity01.GUI_STOP_NOTIFIER;              Activity01.this.myMessageHandler.sendMessage(m);   //将message发送到消息队列                break;               }              else            {             Message m = new Message();             m.what = Activity01.GUI_THREADING_NOTIFIER;             Activity01.this.myMessageHandler.sendMessage(m);    //将message发送到消息队列                                  }                              }                              catch (Exception e)                              {                                  e.printStackTrace();                              }                          }                      }                  }).start();              }          });      }   //通过匿名类复写Handler类中的handleMessage方法,用于接收传递到消息队列中的Message,并进行UI操作。      Handler myMessageHandler = new Handler()        {          // @Override             public void handleMessage(Message msg)            {                switch (msg.what)                {                //ProgressBar已经是对大值                case Activity01.GUI_STOP_NOTIFIER:                    m_ProgressBar.setVisibility(View.GONE);                    m_ProgressBar2.setVisibility(View.GONE);                    Thread.currentThread().interrupt();                    break;                case Activity01.GUI_THREADING_NOTIFIER:                    if (!Thread.currentThread().isInterrupted())                    {                        // 改变ProgressBar的当前值                        m_ProgressBar.setProgress(intCounter);                        m_ProgressBar2.setProgress(intCounter);                                                // 设置标题栏中前景的一个进度条进度值                        setProgress(intCounter*100);                        // 设置标题栏中后面的一个进度条进度值                        setSecondaryProgress(intCounter*100);//                    }                    break;                }                super.handleMessage(msg);           }        };  } 

以上的例子中,子线程只是对进度条的参数进行了变更,并将结果以message形式发送到消息队列中去,子线程的内部并未进行UI操作,而是在重写的Handler的handlerMessage方法中操作了UI界面。
   2. 传递Runnable对象。用于通过Handler绑定的消息队列,安排不同操作的执行顺序。
    Handler对象在进行初始化的时候,会默认的自动绑定消息队列。利用类post方法,可以将Runnable对象发送到消息队列中,按照队列的机制按顺序执行不同的Runnable对象中的run方法。

public class HandlerActivity extends Activity {      /** Called when the activity is first created. */     //声明两个按钮控件      private Button startButton = null;      private Button endButton = null;      @Override     public void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.main);          //根据控件的ID得到代表控件的对象,并未这两个按钮设置相应的监听器          startButton = (Button)findViewById(R.id.startButton);          startButton.setOnClickListener(new StartButtonListener());          endButton = (Button)findViewById(R.id.endButton);          endButton.setOnClickListener(new EndButtonListener());                }      class StartButtonListener implements OnClickListener{           @Override         public void onClick(View v) {              //调用Handler的post方法,将要执行的线程对象添加到队列当中              handler.post(updateThread);          }                }            class EndButtonListener implements OnClickListener{           @Override         public void onClick(View v) {              handler.removeCallbacks(updateThread);          }                }      //创建一个Handler对象      Handler handler  = new Handler();      //将要执行的操作写在线程对象的run方法当中      Runnable updateThread =  new Runnable(){           @Override         public void run() {              System.out.println("UpdateThread");              //在run方法内部,执行postDelayed或者是post方法              handler.postDelayed(updateThread, 3000);          }                };  } 

程序的运行结果就是每隔3秒钟,就会在控制台打印一行UpdateTread。这是因为实现了Runnable接口的updateThread对象进入了空的消息队列即被立即执行run方法,而在run方法的内部,又在3000ms之后将其再次发送进入消息队列中。
   3. Handler和多线程
    post方法虽然发送的是一个实现了Runnable接口的类对象,但是它并非创建了一个新线程,而是执行了该对象中的run方法。也就是说,整个run中的操作和主线程处于同一个线程。
    这样对于那些简单的操作,似乎并不会影响。但是对于耗时较长的操作,当它被加入到消息队列中之后执行会占用很长的时间,以至于处于同一线程的其他操作无法继续执行,就会出现“假死”。为了解决这个问题,就需要使得handler绑定到一个新开启线程的消息队列上,在这个处于另外线程的上的消息队列中处理传过来的Runnable对象和消息。

public class HandlerTest2 extends Activity {       @Override     protected void onCreate(Bundle savedInstanceState) {          // TODO Auto-generated method stub      super.onCreate(savedInstanceState);      setContentView(R.layout.main);      //打印了当前线程的ID      System.out.println("Activity-->" + Thread.currentThread().getId());      //生成一个HandlerThread对象      HandlerThread handlerThread = new HandlerThread("handler_thread");      //在使用HandlerThread的getLooper()方法之前,必须先调用该类的start(),同时开启一个新线程;      handlerThread.start();    //将由HandlerThread获取的Looper传递给Handler对象,即由处于另外线程的Looper代替handler初始化时默认绑定的消息队列来处理消息。      MyHandler myHandler = new MyHandler(handlerThread.getLooper());      Message msg = myHandler.obtainMessage();      //将msg发送到目标对象,所谓的目标对象,就是生成该msg对象的handler对象      Bundle b = new Bundle();      b.putInt("age", 20);      b.putString("name", "Jhon");      msg.setData(b);      msg.sendToTarget();  //将msg发送到myHandler    }            //定义类    class MyHandler extends Handler{      public MyHandler(){                    }          public MyHandler(Looper looper){          super(looper);      }      @Override     public void handleMessage(Message msg) {          Bundle b = msg.getData();          int age = b.getInt("age");          String name = b.getString("name");          System.out.println("age is " + age + ", name is" + name);          System.out.println("Handler--->" + Thread.currentThread().getId());          System.out.println("handlerMessage");          }      }  }

这样,当使用sendMessage方法传递消息或者使用post方法传递Runnable对象时,就会把它们传递到与handler对象绑定的处于另外一个线程的消息队列中,它们将在另外的消息队列中被处理。而主线程还会在发送操作完成时候继续进行,不会影响当前的操作。
    这里需要注意,这里用到的多线程并非由Runnable对象开启的,而是ThreadHandler对象开启的。Runnable对象只是作为一个封装了操作的对象被传递,并未产生新线程
0 0
原创粉丝点击