handler机制的一个引子

在android系统当中,有一个非常重要的铁律,在UI线程之外,是不能修改UI的,在后台线程,新起一个线程,得到的数据结果是不能直接反映在UI上的。
MainThread (UI线程或主线程)和 WorkrThread (除了主线程之外的其他的线程都叫workThread,对一些可能产生阻塞的操作要放在workthread中完成)
workthread从原则上来讲是不允许操作UI的,个别控件除外(ProgressBar)
在一个应用程序当中,UI线程通常用于接收用户的界面输入以及将运算结果反馈给用户

一个问题,workThread中运算,结果无法反馈到UI,又不能把运算的过程放在主线程中,就产生了workThread和mainThread通讯的问题。

handle机制就是解决这一问题的

什么是handler,handler消息处理机制:

handler就是一个消息处理器,handler,looper(循环器),messageQueue 所构成的这样的一个系统,是android系统当中最重要的消息传递,以及消息处理机制。
handler负责把消息对象加入到消息队列当中去,looper(循环器)负责把消息对象从消息队列当中取出。handler负责放,looper负责从消息队列中往外取。
如果消息队列中没有消息对象,那么负责取出消息对象的LOOP的这行代码就会产生阻塞(处于等待的状态),looper把消息对象从消息队列中取出来之后干什么呢?
looper将会调用handler的handlerMessage方法来处理message对象

主线程中 Handler A发了一个消息,Handler B在主线程中能不能接收到这个消息呢?一个handler的实例只能接受到自己发的message的信息,

很多handler共享的是一个messageQueue,通过Message 的what的属性来进行标的,只能收到自己handler相关的message

主线程有一个Looper,是一个死循环,监听消息队列,但又不是额外的线程,但是不会阻塞主线程,Looper由系统来控制的,底层的vm来控制的

并非每个线程都有Looper的实例

handler类的主要作用有两个:

在新启动的线程中发送消息,在主线程中获取、处理消息。
每个线程只拥有一个Looper,loop方法负责读取消息队列中的消息,读到信息之后就把消息交给发送该消息的handler处理

在UI线程中,系统已经初始化了一个Looper对象,因此程序直接创建handler即可,然后通过handler发送处理消息
程序员自己启动的子线程,程序员需要自己创建一个Looper对象,用prepare方法创建looper对象。


示例1(从workThread向mainThread发消息)

public class MainActivity extends Activity {

  private TextView textView;
  private Button button;
  private Handler handler;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    textView = (TextView)findViewById(R.id.textviewId);
    button = (Button)findViewById(R.id.buttonId);
    button.setOnClickListener(new ButtonListener());
    handler = new MyHandler();
  }
  class ButtonListener implements OnClickListener {

    @Override
    public void onClick(View v) {
      Thread thread = new NetWorkThread();
      thread.start();
    }
  }

  class NetWorkThread extends Thread {
    @Override
    public void run() {
      try {
        Thread.sleep( 2 * 1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      String string = "从网络测获取的数据";
      Message msgMessage = handler.obtainMessage();
      msgMessage.obj = string;
      //sendmessage方法无论在主线程中还是workthread中都是可以发送的
      handler.sendMessage(msgMessage);
    }
  }

  class MyHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
      String string = (String)msg.obj;
      //在主线程中就可以随意的操作UI了
      textView.setText(string);
    }
  }
}

示例2(从mainThread向workThread发消息,在workThread中生成handler对象)

public class MainActivity extends Activity {

  private Handler handler;
  private Button button;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    button = (Button)findViewById(R.id.buttonId);
    button.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        Message msg = handler.obtainMessage();
        handler.sendMessage(msg);
      }
    });
    WorkerThread wtThread = new WorkerThread();
    wtThread.start();
  }

  class WorkerThread extends Thread {
    @Override
    public void run() {
      //准备Looper对象
      Looper.prepare();
      //在workThread当中生成一个handler对象
      handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
          System.out.println("收到了消息对象");
        }
      };
      //调用Loop()方法之后,Looper对象不断的从消息队列当中取出消息对象,然后调用handler的handleMessage方法
      //处理消息对象,如果消息队列当中没有消息对象,则线程阻塞
      Looper.loop();
    }
  }

      LOOPER是由系统控制的,底层实现的,不阻塞主线程

      HandlerThread类有Looper对象,不需要prepare
}

posted on 2015-05-20 07:39  太阳星辰  阅读(904)  评论(0编辑  收藏  举报