handler.loop.messageQueue介绍和工作原理

     1.handle的消息传递机制
          安卓的UI线程不是安全的,为了解决这个问题,安卓指定了:只允许UI线程修改UI
          而handle消息传递机制就是另外一种形式的“事件处理”机制,就像各个系统处理进程似的,新启动的线程,可以通过handle传递机制来修改UI界面的值或UI了。
     2.handle 介绍:
  • 在新启动的线程中发送消息
  • 在主线程中获取,处理消息
     在新启动的线程中发送消息;然后再主线程中获取并处理消息。
     为了解决何时发送何时处理,只能通过回调的方式来实现。
     当我们重写了handle类中处理消息的方法(handleMeaage()),然后在新启动的线程中发送消息时,消息会被送到与之关联的MessageQueue,而handle则会不断的从MessageQueue中取出并处理这些消息(这时回调)。

     handle类中有这些用于处理,发送消息的函数:
  • void handleMessage(Message msg):处理消息的回调方法,通常在handle声明后重写;
  • final boolean hasMessages(int what):检索MessageQueque队列中是否包含有参数中的值所对应的Message;
  • final boolean hasMessages(int what,Object object):检索MessageQueque 队列中是否有参数what和对象object所对应的Message;
  • sendEmptyMessage(int what):发送空消息,可以指定message中的what值(ps我认为就不算empty);
  • final boolean sendEmptyMessageDelayed(int what,long delayMilis):延迟多少秒后发送空消息。
例子:使用Timer在新起的线程中定时发送handle消息来动态修改ImageView中的图片资源
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;

import java.util.Timer;
import java.util.TimerTask;


public class MainActivity extends AppCompatActivity {
ImageView imageView;
    int[] number={
            R.mipmap.ic_surface,
            R.mipmap.ic_surface2
    };
    int currentInamgenumber=0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.imageView=(ImageView)findViewById(R.id.imageView);
        final Handler myhandle=new Handler(){
            @Override
            public void handleMessage(Message msg) {
                if(msg.what==0x1){ //如果发送的消息是0x1
                    imageView.setImageResource(number[currentInamgenumber++%number.length]);//则动态修改图片资源
                    //currentInamgenumber余上总数。当当前数为数组长度时,余数为0
                }
            }
        };
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                myhandle.sendEmptyMessage(0x1);//发送what值为0x1的Message
            }
        },0,2400);

    }
}


handle的工作原理:
一:与handle一起工作的组件:
  1. Message:handle用于发送和接收的消息对象。
  2. looper:每个线程只能拥有一个looper,它的loop方法负责读取MessageQueue中的消息,读到消息之后把消息交给发送该消息的Handle来处理。
  3. MessageQueue:消息池,采用先进先出方式来管理消息队列。当创建looper对象时,会在他的构造器中创建MessageQueue对象,而因为looper的构造方法是由private修饰的,所以程序员无法使用looper的构造器来创建looper对象。直接使用即可(在代码处直接写looper.prepare()准备和looper,loop()启动接收消息)
对于handle,它有两个作用,那就是既接收处理消息,也发送消息。由handle发送的消息必须送到这个handle的MessageQueue中,所有在线程中必须得有一个MessageQueue,不然就没地方保存了。MessageQueue又是由Looper来创建管理,所有要想Handle正常工作,就得在线程中拥有一个looper对象。下面列出在两种情况中保证拥有looper:
  • 在UI线程中,系统已经初始化了一个looper对象,所有我们可以直接创建Handle并使用。
  • 在我们自己启动的新线程中,必须自己创建一个looper对象,并启动。(创建looper对象直接调用looper类的方法prepare()就可以)
接着调用looper类的loop()方法来启动looper。loop()是一个死循环,它不断的从MessageQueue中消息,并且发送给发送该条消息的Handle来处理。
二:总结
  • looper:每个线程有且只能有一个looper对象。looper对象构造方法中会创建MessageQueue消息池。looper用于分发MessageQueue中的消息
  • MessageQueue:采用先进先出的方式管理Message队列。有Looper对象来创建和管理
  • Handle:发送和处理消息。发送是指发送给Looper管理的MessageQueue消息池。处理是指处理由looper分发的消息。
三:在线程中使用Handler的步骤:
  1.      调用Looper的prepare()方法为新启动的线程创建Looper对象。looper对象会在构造器重创建MessageQueue消息池
  2. 创建Handler子类的实例。重写handleMessage(Message msg)方法来处理来自其他线程的消息。
  3. 调用Looper的Loop()方法来循环分发处理MessageQueue队列中的消息。


我认为handle写在UI线程。方便,然后在新线程中调用这个handle的send方法来发送消息。而handle会在UI线程中处理这个消息并更改UI。