Android应用中经常需要在多线程中操作UI组件,而多线程操作UI组件会导致安全问题。为了处理这个问题,出现了Handler机制。



使用Handler通常会用到以下函数:

  • post(Runnable)
  • postAtTime(Runnable,long)
  • postDelayed(Runnable long)
  • handlerMessage(Message msg)
  • sendEmptyMessage(int)
  • sendMessage(Message)
  • sendMessageDelayed(Message,long)



Message数据传递:
存放数据

Message msg = new Message();
  
  Bundle b = new Bundle();// 存放数据
  
  b.putString("color", "我的");
  
  msg.setData(b);
  
  myHandler.sendMessage(msg);

接收数据


public void handleMessage(Message msg) {
  
      super.handleMessage(msg);
  
      Bundle b = msg.getData();
  
      String color = b.getString("color");
  
      ...
  
  }

最简单的实例:
通过Handler
Handler属于主线程,即UI线程,因此它能够处理UI组件。


public class HandlerTest extends Activity
  
  {
  
      // 定义周期性显示的图片的ID
  
      int[] imageIds = new int[]
  
      {
  
          R.drawable.java,
  
          R.drawable.ee,
  
          R.drawable.ajax,
  
          R.drawable.xml,
  
          R.drawable.classic
  
      };
  
      int currentImageId = 0;
  
   
  
      @Override
  
      public void onCreate(Bundle savedInstanceState)
  
      {
  
          super.onCreate(savedInstanceState);
  
          setContentView(R.layout.main);
  
          final ImageView show = (ImageView) findViewById(R.id.show);
  
   
  
         //位于主线程,相当于普通的函数,等待被调用,负责UI界面的处理。
  
          final Handler myHandler = new Handler()
  
          {
  
              @Override
  
              public void handleMessage(Message msg)
  
              {
  
                  // 如果该消息是本程序所发送的
  
                  if (msg.what == 0x1233)
  
                  {
  
                      // 动态地修改所显示的图片
  
                      show.setImageResource(imageIds[currentImageId++% imageIds.length]);
  
                  }
  
              }
  
          };
  
          // 新线程,当调用mHandler发送消息时,会自动调用handleMessage()函数
  
          // 定义一个计时器,让该计时器周期性地执行指定任务
  
          new Timer().schedule(new TimerTask()
  
          {
  
              @Override
  
              public void run()
  
              {
  
                  // 发送空消息
  
                  myHandler.sendEmptyMessage(0x1233);
  
              }
  
          }, 0, 1200);
  
   
  
          //回调机制:自己发送Message自己接收。
  
      }
  
  } 
public
   
    
   
   class
   
    
   
   HandlerTest
   
    
   
   extends
   
    
   
   Activity
   
    
   
   {
  
      /** Called when the activity is first created. */
  
      private Button startButton;
  
      private Button endButton;
  
   
  
      @Override
  
      public void onCreate(Bundle savedInstanceState) {
  
          super.onCreate(savedInstanceState);
  
          setContentView(R.layout.main);
  
          //根据id获得控件对象
  
          startButton = (Button)findViewById(R.id.startButton);
  
          endButton = (Button)findViewById(R.id.endButton);
  
          //为控件设置监听器
  
          startButton.setOnClickListener(new StartButtonListener());
  
          endButton.setOnClickListener(new EndButtonListener());
  
      }
  
   
  
      class StartButtonListener implements OnClickListener{
  
          public void onClick(View v) {
  
              //调用Handler的post()方法,将要执行的线程对象放到队列当中
  
              handler.post(updateThread);
  
          }
  
      }
  
   
  
      class EndButtonListener implements OnClickListener{
  
          public void onClick(View v) {
  
              //调用Handler的removeCallbacks()方法,删除队列当中未执行的线程对象
  
              handler.removeCallbacks(updateThread);
  
          }
  
   
  
      }
  
   
  
      //创建Handler对象
  
      Handler handler = new Handler();
  
      //新建一个线程对象
  
      Runnable updateThread = new Runnable(){
  
          //将要执行的操作写在线程对象的run方法当中
  
          public void run(){
  
              System.out.println("updateThread");
  
              //调用Handler的postDelayed()方法
  
              //这个方法的作用是:将要执行的线程对象放入到队列当中,待时间结束后,运行制定的线程对象
  
              //第一个参数是Runnable类型:将要执行的线程对象
  
              //第二个参数是long类型:延迟的时间,以毫秒为单位
  
              handler.postDelayed(updateThread, 3000);
  
          }
  
      };
  
  }



举例:在新建线程中使用Handler
当点击按钮之后,主线程通过Handler把把数据传递到CalThread 线程,CalThread 线程在处理完之后将结果通过Toast显示出来。

public class CalPrime extends Activity
  
  {
  
      static final String UPPER_NUM = "upper";
  
      EditText etNum;
  
      CalThread calThread;
  
      // 定义一个线程类
  
      class CalThread extends Thread
  
      {
  
          public Handler mHandler;
  
   
  
          public void run()
  
          {
  
              Looper.prepare();
  
              mHandler = new Handler()
  
              {
  
                  // 定义处理消息的方法
  
                  @Override
  
                  public void handleMessage(Message msg)
  
                  {
  
                      if(msg.what == 0x123)
  
                      {
  
                          int upper = msg.getData().getInt(UPPER_NUM);
  
                          List<Integer> nums = new ArrayList<Integer>();
  
                          // 计算从2开始、到upper的所有质数
  
                          outer:
  
                          for (int i = 2 ; i <= upper ; i++)
  
                          {
  
                              // 用i处于从2开始、到i的平方根的所有数
  
                              for (int j = 2 ; j <= Math.sqrt(i) ; j++)
  
                              {
  
                                  // 如果可以整除,表明这个数不是质数
  
                                  if(i != 2 && i % j == 0)
  
                                  {
  
                                      continue outer;
  
                                  }
  
                              }
  
                              nums.add(i);
  
                          }
  
                          // 使用Toast显示统计出来的所有质数
  
                          Toast.makeText(CalPrime.this , nums.toString()
  
                              , Toast.LENGTH_LONG).show();
  
                      }
  
                  }
  
              };
  
              Looper.loop();
  
          }
  
      }
  
      @Override
  
      public void onCreate(Bundle savedInstanceState)
  
      {
  
          super.onCreate(savedInstanceState);
  
          setContentView(R.layout.main);
  
          etNum = (EditText)findViewById(R.id.etNum);
  
          calThread = new CalThread();
  
          // 启动新线程
  
          calThread.start();
  
      }
  
      // 为按钮的点击事件提供事件处理函数
  
      public void cal(View source)
  
      {
  
          String num = etNum.getText().toString().trim();
  
          if(!"".equals(num)) {
  
              // 创建消息
  
              Message msg = new Message();
  
              msg.what = 0x123;
  
              Bundle bundle = new Bundle();
  
              bundle.putInt(UPPER_NUM, Integer.parseInt(num));
  
              msg.setData(bundle);
  
              // 向新线程中的Handler发送消息
  
              calThread.mHandler.sendMessage(msg);
  
          }else{
  
              tv.setText("Please input a natural number!");
  
          }
  
      }
  
  }

加上新线程将获取的数据传回主线程:


public class CalPrime extends Activity
  
  {
  
      static final String UPPER_NUM = "upper";
  
      EditText etNum;
  
      TextView tv;
  
      CalThread calThread;
  
      Handler myHandler;
  
      // 定义一个线程类
  
      class CalThread extends Thread
  
      {
  
          public Handler mHandler;
  
   
  
          public void run()
  
          {
  
              Looper.prepare();
  
              mHandler = new Handler()
  
              {
  
                  // 定义处理消息的方法
  
                  @Override
  
                  public void handleMessage(Message msg)
  
                  {
  
                      if(msg.what == 0x123)
  
                      {
  
                          int upper = msg.getData().getInt(UPPER_NUM);
  
                          List<Integer> nums = new ArrayList<Integer>();
  
                          // 计算从2开始、到upper的所有质数
  
                          outer:
  
                          for (int i = 2 ; i <= upper ; i++)
  
                          {
  
                              // 用i处于从2开始、到i的平方根的所有数
  
                              for (int j = 2 ; j <= Math.sqrt(i) ; j++)
  
                              {
  
                                  // 如果可以整除,表明这个数不是质数
  
                                  if(i != 2 && i % j == 0)
  
                                  {
  
                                      continue outer;
  
                                  }
  
                              }
  
                              nums.add(i);
  
                          }
  
                          // 使用Toast显示统计出来的所有质数
  
                          //Toast.makeText(CalPrime.this , nums.toString(), Toast.LENGTH_LONG).show();
  
                          Message mymsg = new Message();
  
                          Bundle b = new Bundle();// 存放数据
  
                          b.putString("result", nums.toString());
  
                          mymsg.setData(b);
  
                          mymsg.what=0x1233;
  
                          myHandler.sendMessage(mymsg);
  
                      }
  
                  }
  
              };
  
              Looper.loop();
  
          }
  
      }
  
      @Override
  
      public void onCreate(Bundle savedInstanceState)
  
      {
  
          super.onCreate(savedInstanceState);
  
          setContentView(R.layout.main);
  
          etNum = (EditText)findViewById(R.id.etNum);
  
          tv=(TextView)findViewById(R.id.tv);
  
          calThread = new CalThread();
  
          // 启动新线程
  
          calThread.start();
  
   
  
          myHandler = new Handler()
  
          {
  
              @Override
  
              public void handleMessage(Message msg)
  
              {
  
                  // 如果该消息是本程序所发送的
  
                  if (msg.what == 0x1233)
  
                  {
  
                      // 动态地修改所显示的图片
  
                      Bundle b = msg.getData();
  
                      String result = b.getString("result");
  
                      tv.setText(result.substring(1,result.length()-1));
  
                  }
  
              }
  
          };
  
      }
  
   
  
      // 为按钮的点击事件提供事件处理函数
  
      public void cal(View source)
  
      {
  
          String num = etNum.getText().toString().trim();
  
          if(!"".equals(num)) {
  
              // 创建消息
  
              Message msg = new Message();
  
              msg.what = 0x123;
  
              Bundle bundle = new Bundle();
  
              bundle.putInt(UPPER_NUM, Integer.parseInt(num));
  
              msg.setData(bundle);
  
              // 向新线程中的Handler发送消息
  
              calThread.mHandler.sendMessage(msg);
  
          }else{
  
              tv.setText("Please input a natural number!");
  
          }
  
      }
  
  }