温故知新.Handler消息传递机制.

忙里抽闲,赶紧打开电脑温故下学过用过而又快被时间冲掉的知识点…..。

直奔主题

出于性能优化考虑,Android系统的UI的操作并不是线程安全的,这意味着如果有多个线程并发操作UI组件,则可能导致线程安全带问题。为了解决这个问题,Android制定了一条简单的规则:只允许UI线程修改Activity里的UI组件。

当一个程序第一次启动时,Android会同时启动一条主线程(Main Thread),主线程主要负责处理与UI相关的事件,如用户的按键事件、用户接触屏幕的事件及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。So,主线程通常又被叫作UI线程。

Android的消息传递机制是另一种形式的"事件处理",这种机制主要是为了解决Android应用的多线程问题
Android平台只允许UI线程修改Activity里的UI组件,这样就会导致新启动的线程无法动态
改变界面组件的属性值。但在实际Android应用开发中,尤其是涉及动画的游戏开发中,需要让新启动的线程
周期性地改变界面组件的属性值,这就需要借助于Handler的消息传递机制来实现。

Handler类的主要作用有两个

1. 在新启动的线程中发送消息。 2. 在主线程中获取、处理消息。

说上去看似很简单,似乎只要分成两步即可:

在新启动的线程中发送消息;然后在主线程中获取并处理消息。

但这个过程涉及两个问题:

1.新启动的线程何时发送消息呢?
2.主线程何时去获取并处理消息呢?

这个时机显然不好控制,为了让主线程能”适时”地处理新启动的线程所发送的消息,显然只能通过回调的方式来实现–使用的时候只要重写Handler类中处理消息的方法,当新启动的线程发送消息时,消息会发送到与之关联的MessageQueue,而Handler会不断地从MessageQueue中获取并处理消息,这就会导致Handler类中处理消息的方法被回调。

Handler类包含如下方法用于发送、处理消息。<看过源码的人都知道>

    //处理消息的方法,该方法通常用于被重写
    @Override
    public void handleMessage(Message msg) {
            super.handleMessage(msg);
       }

        //检查消息队列中是否包含what属性为指定值得消息
    public final boolean hasMessages(int what) {
            return mQueue.hasMessages(this, what, null);
        }
    //检查消息队列中是否包含what属性为指定值且object属性为指定对象的消息
    public final boolean hasMessages(int what, Object object) {
            return mQueue.hasMessages(this, what, object);
        }

    //多个重载obtainMessage 获取消息。
    public final Message obtainMessage()
    {
        return Message.obtain(this);
    }
    public final Message obtainMessage(int what)
    {
        return Message.obtain(this, what);
    }
     public final Message obtainMessage(int what, Object obj)
    {
        return Message.obtain(this, what, obj);
    }
     public final Message obtainMessage(int what, int arg1, int arg2)
    {
        return Message.obtain(this, what, arg1, arg2);
    }
     public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
    {
        return Message.obtain(this, what, arg1, arg2, obj);
    }
    //发送空消息
     public final boolean sendEmptyMessage(int what)
    {
        return sendEmptyMessageDelayed(what, 0);
    }
    //指定多少毫秒之后发送空消息
    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }
    //立即发送消息
     public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
    //指定多少毫秒之后发送消息
     public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

有了以上这些方法,程序可以方便地利用Handler来进行消息传递。

说了那么多没卵用的!

    没人给勇气都看不下去了.....

客官~ 
    骚等.... 
        小二马上附上一份极间的代码案例!

自动播放动画实例:

实例通过一个新线程来周期性地修改ImageView所显示的图片,通过这种方式来开发一个动画效果,
为了演示写的非常简单,程序只是在界面布局中定义了ImageView组件,就不贴XML布局代码了。
//主程序使用java.util包下的Timer来周期性的执行指定任务:

public class mainsActivity extends Activity {
    //定义周期性显示的图片 ID
    int[] imageIds =new int[]{
            R.drawable.one,
            R.drawable.two,
            R.drawable.three,
            R.drawable.four,
            R.drawable.five
    };
    int currentImageId =0;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
      final ImageView show=(ImageView) findViewById(R.id.show);
      final  Handler mHandler = new Handler(){
          @Override
          public void handleMessage(Message msg) {
              //如果该消息是本程序所发送的
              if (msg.what == 0x1233){
                  //动态地修改所显示的图片
                  show.setImageResource(imageIds[currentImageId++ % imageIds.length]);
              }
          }
      };
      //定义一个计时器,让该计时器周性地执行任务
        new Timer().schedule(new TimerTask(){
            @Override
            public void run() {
                //发送消息
                mHandler.sendEmptyMessage(0x1233);
            }
        },0,1500);
    }
}

小实例细说

上实例中通过Timer周期性地执行指定任务,Timer对象可调度TimerTask对象,TimerTask对象的本质就是启动一条线程,原因Android不允许在新线程中访问Activity里的界面组件,因此只能在新线程里发送一条消息,通知系统更新ImageView组件。

以上代码重写了Handler的handleMessage(Message msg)方法,该方法用于处理消息——当新线程发送消息时,该方法会被自动回调,handlerMessage(Message msg)方法依然位于主线程中,所以可以动态地修改ImageView组件的属性。

这就实现了小实例所要达到的效果:

    由新线程来周期性的修改ImageView属性,从而实现动画效果,运行上面的小实例,达到5张图片交替显示的动态效果。

明天待续Handler 、Loop、MessageQueue

他们之间是怎么成为老铁的………

你可能感兴趣的:(线程篇)