UI线程安全
出于性能优化的角度,Android对于UI界面的操作不是线程安全的!这就意味着我们不能多少线程并发地操作UI界面,不然会导致线程安全问题。为了避免出现这样的情况,android制定了一个规定,只有UI线程才能修改Activity里面的UI组件。
何为UI线程呢?UI线程也叫主线程(Main Thread),在程序第一次启动后,android就会帮我们自动生成并启动一条线程,这就是主线程,主线程主要负责跟UI相关的事件,如响应用户的按钮事件,用户接触屏幕事件及屏幕绘图事件。并把相关的事件分发给对应的组件去处理。
Handler消息传递机制
Handler类
前面说了,android只允许UI线程(主线程)修改相关的UI界面,但如果所有程序涉及到修改UI线程的操作都在UI线程操作的话,那毫无疑问,将加大UI线程的负担,而且更有可能因为执行了耗时太久的操作,而造成手机来不及响应用户的操作,要知道android可是要求实时性高的系统。很容易就造成ANR异常。所以我们需要将涉及到界面修改又耗时比较久的操作独立成为一个线程,而通过线程之间的通信将独立出来的线程执行完的消息传到主线程中,再让主线程去修改相关的UI界面。这样岂不是最好的解决方法,而线程之间的通信我们就不能不说说Handler类了。
Handler类的功能
- 在新启动的线程中发送消息
- 在主线程中获取并处理消息
要实现这样的功能,我们就需要运用回调的方式来重写handler类中处理消息的方法,用来到时被回调来处理所传来的消息。而发送消息则需要借助message来传递。接下来就让我们来看看具体的例子吧。
自动播放图片的动画效果
效果如下:
首先我们需要在activity_main中定义一个ImageView控件,这个太简单就不写出来了。
接下来便在程序中用Timer定时器来定义一个时间,用Hanler消息传递机制来传送信息给主线程,说明一下,在这里new TimerTask()操作会定义一个线程,这个线程独立于主线程。
//图片ID组
int[] imageIds = new int[]{
R.drawable.rabit,
R.drawable.cat,
R.drawable.dog
};
int currentImageId = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ImageView show = (ImageView) findViewById(R.id.iv);
final Handler myHandler = new Handler(){
@Override
public void handleMessage(Message msg){
//如果该消息是本程序所改发送的
if(msg.what == 0x123){
//动态地修改所显示的图片
show.setImageResource(imageIds[currentImageId++
%imageIds.length]);
}
}
};
//定义一个计时器
new Timer().schedule(new TimerTask(){
@Override
public void run(){
myHandler.sendEmptyMessage(0x123);
}
},0,2000);
}