忙里抽闲,赶紧打开电脑温故下学过用过而又快被时间冲掉的知识点…..。
出于性能优化考虑,Android系统的UI的操作并不是线程安全的,这意味着如果有多个线程并发操作UI组件,则可能导致线程安全带问题。为了解决这个问题,Android制定了一条简单的规则:只允许UI线程修改Activity里的UI组件。
当一个程序第一次启动时,Android会同时启动一条主线程(Main Thread),主线程主要负责处理与UI相关的事件,如用户的按键事件、用户接触屏幕的事件及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。So,主线程通常又被叫作UI线程。
Android的消息传递机制是另一种形式的"事件处理",这种机制主要是为了解决Android应用的多线程问题
Android平台只允许UI线程修改Activity里的UI组件,这样就会导致新启动的线程无法动态
改变界面组件的属性值。但在实际Android应用开发中,尤其是涉及动画的游戏开发中,需要让新启动的线程
周期性地改变界面组件的属性值,这就需要借助于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张图片交替显示的动态效果。